var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var bodyParser = require('body-parser');
var fs = require('fs');
var http = require('http');
var formidable = require('formidable');
var kafka = require('kafka-node');

//引用数据库模块
var db_util = require('./db_utility');
var xlsx = require('node-xlsx');
const { setUncaughtExceptionCaptureCallback, off } = require('process');

function skipLog(req) {
  return req.method == 'POST' || req.method == 'OPTIONS';
}

var app = express();
app.use(logger('dev', {skip:skipLog}));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(express.json({limit: '150mb'}));
app.use(express.urlencoded({ limit: '150mb', extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


//设置跨域访问
app.all('*', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
  res.header("X-Powered-By",' 3.2.1');
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

var g_cncOeeMonthBusy = false;
var g_nWaitTime = 180 * 1000; // 最大等待时间
var g_nOffTime = 600 * 1000;  // 最小关机时间间隔
var g_lastUpdateTime = 0; // 上一次数据更新时间，如果超过3分钟没有更新就认为关机了。
var g_userInfo = new Array();


app.post('/Login', function(req, res) {
  console.log('Login from ' + req.ip);
  var body = req.body;
  var sql = "select * from employee where job_no = '" + body.name + "'";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      var json = {};
      if( sucData.length > 0 )
      {
        if(sucData[0].password == body.password)
        {
          json["result"] = "ok";
          json["name"] = sucData[0].name;
          json["name_PY"] = sucData[0].name_PY;
          json["job_no"] = sucData[0].job_no;
          json["department"] = sucData[0].department;
          json["department_abb"] = sucData[0].department_abb;
          json["role"] = sucData[0].role;
          json["level"] = sucData[0].level;
          json["remark"] = sucData[0].remark;

          var insert = true;
          for(var i=0; i<g_userInfo.length; i++)
          {
            if( g_userInfo[i]['job_no'] == json["job_no"] )
            {
              console.log('上一次登录地址：' + g_userInfo[i]["ip"]);
              insert = false;
              var date = new Date();
              g_userInfo[i]["name"] = sucData[0].name;
              g_userInfo[i]["job_no"] = sucData[0].job_no;
              g_userInfo[i]["level"] = sucData[0].level;
              g_userInfo[i]["ip"] = req.ip;
              g_userInfo[i]["role"] = sucData[0].role;
              g_userInfo[i]["remark"] = sucData[0].remark;
              g_userInfo[i]["loginTime"] = getMonthDayTime(date, 1, 1);
              console.log(g_userInfo[i]);
              break;
            }
          }
          if( insert == true )
          {
            var msg = {};
            var date = new Date();
            msg["name"] = sucData[0].name;
            msg["job_no"] = sucData[0].job_no;
            msg["level"] = sucData[0].level;
            msg["ip"] = req.ip;
            msg["role"] = sucData[0].role;
            msg["remark"] = sucData[0].remark;
            msg["loginTime"] = getMonthDayTime(date, 1, 1);
            g_userInfo.push(msg);
            console.log(msg);
          }
        }
        else
        {
          json["result"] = "error";
          json["description"] = "password error";
          console.log(body.name + '登录，但密码错误');
        }
      }
      else
      {
        json["result"] = "error";
        json["description"] = "not found the job_no " + body.name;
        console.log(json);
      }
      res.status(200);
      res.json(json);
    },
    (errData) =>
    {
      console.log(errData.message);
      res.status(200);
      json["result"] = "error";
      json["errorCode"] = "1";
      json["description"] = "not found the job_no";
      res.json(json);
    }
  );
})

app.post('/unLogin', function(req, res) {
  for(var i=0; i<g_userInfo.length; i++)
  {
    if( g_userInfo[i]['ip'] == req.ip )
    {
      console.log(req.ip + ' ' + g_userInfo[i]["name"] + " 已注销");
      g_userInfo.splice(i, 1);
      break;
    }
  }
  res.status(200);
  res.json({"result":"ok"});
})

function CheckUserInfo(req)
{
  var i = 0;
  var json = {};
  if( req.body.job_no != undefined )
  {
    for(i=0; i<g_userInfo.length; i++)
    {
      if( g_userInfo[i]['job_no'] == req.body.job_no )
      {
        json["name"] = g_userInfo[i]["name"];
        json["job_no"] = g_userInfo[i]["job_no"];
        json["remark"] = g_userInfo[i]["remark"];
        json["isManager"] = g_userInfo[i]["remark"].includes('部門主管');
        break;
      }
    }
  }
  else
  {
    i = g_userInfo.length;
    json["isManager"] = true; // 不设置工号就默认有主管权限
  }
  if( i == g_userInfo.length )
  {
    for(i=0; i<g_userInfo.length; i++)
    {
      if( g_userInfo[i]['ip'] == req.ip )
      {
        json["name"] = g_userInfo[i]["name"];
        json["job_no"] = g_userInfo[i]["job_no"];
        break;
      }
    }
  }
  return json;
}

app.post('/CheckUserPassword',function(req,res){
  var body = req.body;
  var sql = "select * from employee where job_no = '" + body.name +"'";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      if( sucData.length > 0 )
      {
        if(sucData[0].password == body.password)
          {
            res.status(200);
            res.json({"result":"ok"});
          }
          else
          {
            res.status(200);
            res.json({"result":"error", "errorCode": "1", "description": "the password is wrong"});
          }
      }
      else
      {
        res.status(200);
        res.json({"result":"error", "errorCode": "2", "description": "not found the job_no"});
      }
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "errorCode": "3", "description":errData.message});
      console.log(errData.message);
    }
  );
})

app.post('/QueryUser', function(req, res) {
  var body = req.body;
  var sql = "select name, name_PY, job_no, department, department_abb, role, level, password, remark, wechat, mail, mobile from employee";
  if( body.level != undefined )
  {
    if( body.level.length > 0 )
      sql += " where level = " + body.level + "";
  }
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      var json = {};
      var array = new Array();
      if( sucData.length > 0 )
      {
        var go = 0;
        var filter = "";
        if( body.filter != undefined )
          filter = body.filter;
        var filter2 = "";
        if( body.filter2 != undefined )
          filter2 = body.filter2;
         sucData.forEach(element => {
          go = 0; 
          if( filter.length > 0 || filter2.length > 0 )
          {
            if( filter.length > 0 )
            {
              if( element.remark.indexOf(filter) >= 0 )
                go += 1;
            }
            if( filter2.length > 0 )
            {
              if( element.remark.indexOf(filter2) >= 0 )
                go += 1;
            }
          }
          else
          {
            go = 2;
          }
          if( go > 0 )
            array.push(element);
        });
      }
      json["result"] = "ok";
      json["order"] = array;
      res.status(200);
      res.json(json);
      //console.log('query users: ' + array.length);
    },
    (errData) =>
    {
      console.log(errData.message);
      res.status(200);
      json["result"] = "error";
      json["errorCode"] = "1";
      json["description"] = errData.message;
      res.json(json);
    }
  );
})

app.post('/AddUser',function(req,res){
  var body = req.body;
  var sql = "select * from employee where job_no = '" + body.job_no +"'";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      if( sucData.length > 0 )
      {
        res.status(200);
        res.json({"result":"error", "errorCode": "1", "description": "the job_no exists already"});
      }
      else
      {
        var wechat = body.wechat;
        if(wechat==null)
          wechat = "";
        sql = "insert into employee (name, name_PY, job_no, department, department_abb, role, level, password, remark, wechat, mail, mobile) values('"+body.name+"', '"+body.name_PY+"', '"+body.job_no+"', '"+body.department+"', '"+body.department_abb+"', '"+body.role+"', '"+body.level+"', '"+body.password+"', '"+body.remark+"', '"+wechat+"', '"+body.mail+"', '"+body.mobile+"')";
        db_util.ExecuteSQL(sql, null,
          (suc) => 
          {
            res.status(200);
            res.json({"result":"ok"});
          },
          (err) =>
          {
            res.status(200);
            res.json({"result":"error", "errorCode": "2", "description": err.message});
          }
        );
      }
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "errorCode": "3", "description": errData.message});
      console.log(errData.message);
    }
  );
})

app.post('/UpdateUser',function(req,res){
  var body = req.body;
  var flag = false;
  var sql = "Update employee set ";
  if( body.job_no == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"the job_no is not found"});
    return;
  }
  if( body.name != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "name = '"+body.name+"'";
    flag = true;
  }
   if( body.name_PY != undefined)
   {
    if(flag)
      sql += ", ";
    sql += "name_PY = '"+body.name_PY+"'";
    flag = true;
   }
  if( body.department != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "department = '"+body.department+"'";
    flag = true;
  }
  if( body.department_abb != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "department_abb = '"+body.department_abb+"'";
    flag = true;
  }
  if( body.role != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "role = '"+body.role+"'";
    flag = true;
  }
  if( body.level != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "level = "+body.level+"";
    flag = true;
  }
  if( body.password != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "password = '"+body.password+"'";
    flag = true;
  }
  if( body.remark != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "remark = '"+body.remark+"'";
    flag = true;
  }
  if( body.wechat != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "wechat = '"+body.wechat+"'";
    flag = true;
  }
  if( body.mail != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "mail = '"+body.mail+"'";
    flag = true;
  }
  if( body.mobile != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "mobile = '"+body.mobile+"'";
    flag = true;
  }
  if(flag)
  {
    sql += " where job_no = '" + body.job_no +"'";
    db_util.ExecuteSQL(sql, null,
      (sucData) => 
      {
        console.log(sucData.message);
        if(body.name != undefined)
        {
          sql = "update machining_engineer set name = '"+ body.name +"' where job_no = '"+ body.job_no +"'";
          db_util.ExecuteSQL(sql, null,
            (suc) =>
            {
              res.status(200);
              if( sucData.affectedRows > 0)
                res.json({"result":"ok", "changedRows":sucData.changedRows});
              else
                res.json({"result":"error", "description":"not find the job_no"});
            },
            (err) =>
            {
              res.status(200);
              if( sucData.affectedRows > 0)
                res.json({"result":"ok", "changedRows":sucData.changedRows});
              else
                res.json({"result":"error", "description":"not find the job_no"});
            }
          );
        }
        else
        {
          res.status(200);
          if( sucData.affectedRows > 0)
            res.json({"result":"ok", "changedRows":sucData.changedRows});
          else
            res.json({"result":"error", "description":"not find the job_no"});
        }
      },
      (errData) =>
      {
        res.status(200);
        res.json({"result":"error", "description":errData.message});
        console.log(sql);
      }
    );
  }
  else
  {
    res.status(200);
    res.json({"result":"error", "description":"no column was matched to update"});
    console.log(sql);
  }
})

app.post('/DeleteUser',function(req,res){
  var body = req.body;
  var sql = "delete from employee where job_no = '" + body.job_no +"'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      res.status(200);
      if(sucData.affectedRows>0)
        res.json({"result":"ok"});
      else
        res.json({"result":"error", "description":"not find the job_no"});
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "description":errData.message});
      console.log(errData.message);
    }
  );
})

app.post('/AddWorkFile',function(req,res){
  var body = req.body;
  var unionorder = body.unionorder;
  var workorder = body.workorder;
  var filepath = body.filepath;
  if(unionorder == null || workorder == null || filepath == null)
  {
    res.status(200);
    res.json({"result":"error", "errorCode": "1", "description": "not found the matched column"});
    return;
  }
  var sql = "select * from machining_files where union_order = '" + unionorder + "' and sheet_order = '" + workorder +"'";
  if( unionorder != "kanban" )
    sql += " and file_path = '" + filepath + "'";
  db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      if( suc.length == 0 )
      {
        sql = "insert into machining_files (union_order, sheet_order, file_path, file_name, upload_time, file_status) values('"+ unionorder + "', '" + workorder + "', '" + filepath + "', '" + body.filename +"', '"+body.uploadtime+"', '"+body.filestatus+"')";
        db_util.ExecuteSQL(sql, null,
          (sucData) => 
          {
            console.log(sql);
            res.status(200);
            res.json({"result":"ok"});
          },
          (errData) =>
          {
            res.status(200);
            res.json(errData.message);
          }
        );
      }
      else
      {
        if( unionorder == "kanban" )
          sql = "update machining_files set file_path = '"+ filepath +"', file_name = '"+ body.filename +"', upload_time = '"+ body.uploadtime +"' where union_order = '" + unionorder + "' and sheet_order = '" + workorder +"'";
        else
          sql = "update machining_files set file_name = '"+body.filename+"', upload_time = '"+body.uploadtime+"', file_status = '"+body.filestatus+"', remark = '"+body.remark+"' where union_order = '" + unionorder + "' and sheet_order = '" + workorder +"' and file_path = '" + filepath + "'";
        db_util.ExecuteSQL(sql, null,
          (suc2) =>
          {
            res.status(200);
            res.json({"result":"ok"});
          },
          (err2) =>
          {
            res.status(200);
            res.json({"result":"error", "errorCode": "2", "description": err2.message});
          }
        );
      }
    },
    (err) =>
    {
      res.status(200),
      res.json({"result":"error", "errorCode": "3", "description": err.message});
    }
  );
})

app.post('/UpdateWorkFile', async (req,res) => {
  var body = req.body;
  var sql = "Update machining_files set ";
  sql += body.name;
  sql += " = '"+ body.newValue +"'";
  var parseFile = false;
  if( body.name2 != undefined && body.newValue2 != undefined)
  {
    sql += ", "
    sql += body.name2;
    sql += " = '"+ body.newValue2 +"'";
    if( body.name2 == "file_status" && body.newValue2 == '1' )
      parseFile = true;
  }
  sql += " where id = '"+ body.id +"'";
  console.log(sql);
  try
  {
    await db_util.query(sql);
    if( body.name == "file_status" && body.newValue == '1' ) // 审核通过
      parseFile = true;
    if( parseFile == true )
    {
      sql = "select * from machining_files where id = '"+ body.id +"'";
      let suc = await db_util.query(sql);
      var bomFile = suc[0].file_path;
      var i = bomFile.lastIndexOf('.');
      if( i > 1 )
      {
        var ext = bomFile.substr(i+1).toLowerCase();
        if( ext == 'pdf' )
        {
          setTimeout(function() { ParsePdfFile(suc[0].union_order, bomFile); }, 1000);
          console.log('Prepare to parse: ' + bomFile);
        }
        else if( ext == 'xlsx' || ext == 'xls' )
        {
          setTimeout(function() { ParseBOMFile(bomFile); }, 1000);
          console.log('Prepare to parse: ' + bomFile);
        }
        else if( ext == 'stp' )
        {
          i = await ValidDesignFiles(suc[0].union_order);
        }
      }
    }
    if( (body.name == "file_status" && body.newValue == '2') || (body.name2 == "file_status" && body.newValue2 == '2') )
    {
      sql = "select * from machining_files where id = '"+ body.id +"'";
      let suc2 = await db_util.query(sql);
      if( suc2[0].file_status == 2 )
      {
        await ValidDesignFiles(suc2[0].union_order);
      }
    }
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('UpdateWorkFile error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description": error.message});
  }
})

app.post('/DeleteWorkFile',function(req,res){
  var sql = "select * from machining_files where id = '" + req.body.id +"'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      if(sucData.length > 0)
      {
        var filePath = sucData[0].file_path;
        fs.unlink(filePath, function(err2) {
          if(err2)
          {
            console.log('Failed to delete the file: ' + filePath);
          }
          else
          {
            console.log('Succeeded to delete the file: ' + filePath);
          }
        })
        sql = "delete from machining_files where id = '" + req.body.id +"'";
        db_util.ExecuteSQL(sql, null,
          (suc) =>
          {
            res.status(200);
            res.json({"result":"ok"});
          },
          (err) =>
          {
            res.status(200);
            res.json({"result":"error", "description":"failed to delete the file"});
          }
        );
      }
      else
      {
        res.status(200);
        res.json({"result":"error", "description":"not find the id"});
      }
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "description":errData.message});
      console.log(errData.message);
    }
  );
})

app.post('/QueryWorkFiles', function(req, res) {
  var body = req.body;
  var unionorder = body.unionorder;
  var workorder = body.workorder;
  var sql = "select id, file_path, file_name, file_status, upload_time, remark from machining_files where union_order = '" + unionorder + "' and sheet_order = '"+ workorder +"'";
  console.log('QueryWorkFiles: ' + unionorder + ', ' + workorder);
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      var json = {};
      var array = new Array();
      sucData.forEach(element => {
        array.push(element);
      });
      json["result"] = "ok";
      json["files"] = array;
      res.status(200);
      res.json(json);
      console.log('query result: ' + array.length);
    },
    (errData) =>
    {
        console.log(errData.message);
        res.status(200);
        json["result"] = "error";
        json["errorCode"] = "1";
        json["description"] = "not found the user";
        res.json(json);
    }
  );
})

app.post('/QueryUnionOrder', async (req, res) => {
  var body = req.body;
  var json = {};
  var array = new Array();
  var stage = -1;
  var i = 0, j = 0, k = 0;
  if( body.stage != undefined )
  {
    stage = parseInt(body.stage);
    if( isNaN(stage) )
      stage = -1;
  }
  var sql = "stage = "+ body.stage +", stageValue = "+ body.stageValue +"";
  if( body.status != undefined )
    sql += ", status = "+ body.status +"";
  if( body.cnc != undefined )
    sql += ", cnc = "+ body.cnc +"";
  if( body.job_no != undefined )
    sql += ", job_no = "+ body.job_no +"";
  if( body.workstatus != undefined )
    sql += ", workstatus = "+ body.workstatus +"";
  if( body.warehouse != undefined )
    sql += ", warehouse = "+ body.warehouse +"";
  console.log(sql + ', QueryUnionOrder, from ' + req.ip);
  sql = "select * from machining_sheet where type_flag = '1'";
  if( body.cnc != undefined )
  {
    if( body.cnc.length > 0 && body.cnc != 'All' )
      sql += " and cnc_name = '"+ body.cnc +"'";
  }
  var userInfo = CheckUserInfo(req);
  if( userInfo["isManager"] == false && stage == 4 ) // stage = 4：二次加工
  {
    sql += " and engineer_ercijiagong like '%"+ userInfo["name"] +"%'";
    console.log(sql);
  }
  try
  {
    var sql2 = sql;
    sql = "select * from machining_union_sheet";
    if( body.status != undefined ) // 0/进行中；1/已完成；2/取消
    {
        if( body.status == 0 )
          sql += " where status = 0";
        //else if( body.status == 1 )
        //  sql += " where status = 1";
        else if( body.status == 2 )
          sql += " where status = 2";
        else if( body.status == 10 )
          sql += " where status = 0";
        /*else if( body.status == 20 )
          sql += " where status != 1";
        else if( body.status == 21 )
          sql += " where status != 0";*/
    }
    if( userInfo["isManager"] == false && stage == 0 )
    {
      if( sql.indexOf('where') > 0 )
        sql += " and engineer like '%"+ userInfo["name"] +"%'";
      else
        sql += " where engineer like '%"+ userInfo["name"] +"%'";
    }
    console.log(sql);
    sql += " order by delivery_date ASC"
    let sucData = await db_util.query(sql);
    sql = "select * from machining_engineer";
    if( req.body.type != undefined )
      sql += " where type = '"+ req.body.type +"'";
    else if( stage == 4 )
      sql += " where type = 'engineer_ercijiagong'";
    else
      sql += " where type = 'engineer'";
    let suc1 = await db_util.query(sql);
    for(j=0; j<sucData.length; j++)
    {
      sql = sql2 + " and union_order = '"+ sucData[j].union_order +"'";
      if( stage > 0 )
        sql += " and status = '"+ stage +"'";
      let suc2 = await db_util.query(sql);
      if( suc2.length == 0 && stage > 0 )
        continue;
      // 先判断提示tip的值
      sucData[j].tip = "";
      // 先检查是否要设置new标记
      if( body.job_no != undefined ) // 员工
      {
        if( sucData[j].other_remark != '' )
        {
          sucData[j].tip = "2";
        }
        else
        {
          sql = "select id from machining_files where union_order = '"+ sucData[j].union_order +"' and file_status = 2";
          let succ3 = await db_util.query(sql);
          if( succ3.length > 0 )
            sucData[j].tip = "2";
        }
      }
      else
      {
        sql = "select id from machining_files where union_order = '"+ sucData[j].union_order +"' and file_status = 0";
        let succ4 = await db_util.query(sql);
        if( succ4.length > 0 )
          sucData[j].tip = "2";
      }
      // 再检查是否有提醒标记，此标记优先
      if( stage == 1 ) // 编程
      {
        for(i=0; i<suc2.length; i++)
        {
          if( suc2[i].code_end_date == '' )
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if( i == suc2.length )
        {
          for(i=0; i<suc2.length; i++)
          {
            if( suc2[i].remark != '' )
            {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      }
      else if( stage == 2 ) // 加工
      {
        for(i=0; i<suc2.length; i++)
        {
          if( suc2[i].end_date == '' )
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if( i == suc2.length )
        {
          for(i=0; i<suc2.length; i++)
          {
            if( suc2[i].remark != '' )
            {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      }
      else if( stage == 3 ) // 品检
      {
        for(i=0; i<suc2.length; i++)
        {
          if( suc2[i].check_date == '' )
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if( i == suc2.length )
        {
          for(i=0; i<suc2.length; i++)
          {
            if( suc2[i].remark != '' )
            {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      }
      else if( stage == 4 ) // 二次加工
      {
        for(i=0; i<suc2.length; i++)
        {
          if( suc2[i].machine_end_date_2 == '' )
          {
            sucData[j].tip = "1";
            break;
          }
        }
        if( i == suc2.length )
        {
          for(i=0; i<suc2.length; i++)
          {
            if( suc2[i].remark != '' )
            {
              sucData[j].tip = "2";
              break;
            }
          }
        }
      }
      /*if( stage == 1 ) // 编程
      {
        for(i=0; i<suc2.length; i++)
        {
          if( suc2[i].cnc_name == '' )
          {
            break;
          }
        }
        if( i < suc2.length )
        {
          console.log(sucData[j].union_order + ', 编程状态为1但是没有设置机台号，略过');
          continue;
        }
      }*/
      // element.engineer的值需要从suc1中查找
      var engineer = "";
      for(i=0; i<suc1.length; i++)
      {
        if( sucData[j].union_order == suc1[i].union_order )
        {
          if( engineer.length > 0 )
            engineer += ","
          engineer += suc1[i].name;
        }
      }
      sucData[j].engineer = engineer;
      var haveJiagongjian = false; // 一些不满足要求的工联单就不要了
      if( engineer.length == 0 )
      {
        haveJiagongjian = true;
      }
      else if( body.status != undefined ) // 主管审核
      {
        haveJiagongjian = true;
      }
      else
      {
        for(k=0; k<suc2.length; k++)
        {
          if( req.body.workstatus != undefined )
          {
            if( suc2[k].status != req.body.workstatus ) // 只要有一条加工件的状态不符合要求，该工联单就不要了
              break;
          }
          else
          {
            haveJiagongjian = true;
            break;
          }
        }
      }
      if( haveJiagongjian == true ) // 检查治具状态：未入库/未领取/部分领取/已领取
      {
        if( req.body.warehouse != undefined )
        {
          if( req.body.warehouse == '0' ) // 查找未入库的工联单
          {
            if( sucData[j].ruku_time.length > 0 )
              haveJiagongjian = false;
          }
          else if( req.body.warehouse == '1' ) // 查找未领取的工联单
          {
            var count = parseInt(sucData[j].lingqu_count);
            if( isNaN(count) )
              count = 0;
            if( count > 0 || sucData[j].ruku_time.length == 0 )
              haveJiagongjian = false;
          }
          else if( req.body.warehouse == '2' ) // 查找部分领取的工联单
          {
            var count = parseInt(sucData[j].lingqu_count);
            if( isNaN(count) )
              count = 0;
            var quatity = parseInt(sucData[j].quatity);
            if( count == 0 || count == quatity )
              haveJiagongjian = false;
          }
          else if( req.body.warehouse == '3' ) // 查找已领取的工联单
          {
            var count = parseInt(sucData[j].lingqu_count);
            if( isNaN(count) )
              count = 0;
            var quatity = parseInt(sucData[j].quatity);
            if( count < quatity )
              haveJiagongjian = false;
          }
        }
      }
      if( haveJiagongjian == true ) // 检查阶段
      {
        if( stage >= 0 )
        {
          if( sucData[j].stage.charAt(stage) != req.body.stageValue )
          {
            haveJiagongjian = false;
            //console.log(sucData[j].union_order + '，工单状态' + sucData[j].stage + '[' + stage + ']不等于' + req.body.stageValue + '，略过');
          }
        }
      }
      if( haveJiagongjian == true )
      {
        if( stage == 4 ) // 二次加工
        {
          for(k=0; k<suc2.length; k++)
          {
            if( sucData[j].union_order == suc2[k].union_order )
            {
              break;
            }
          }
          if( k == suc2.length )
          {
            haveJiagongjian = false;
            console.log(sucData[j].union_order + '大表中没有二次加工信息，略过');
          }
        }
      }
      if( haveJiagongjian == true )
      {
        array.push(sucData[j]);
      }
    }
    if( body.status == 1 || body.status == 10 )
    {
      sql = "select * from machining_union_sheet where status = 1 OR stage = '0000000100'";
      sucData = await db_util.query(sql);
      sucData.forEach(element => {
        element["status"] = 1;
        array.push(element);
      });
    }
    json["result"] = "ok";
    json["count"] = array.length;
    json["order"] = array;
    res.status(200);
    res.json(json);
    //console.log('get result: ' + array.length);
  }
  catch(error)
  {
    console.log('QueryUnionOrder failed, ' + error.message);
    res.status(200);
    json["result"] = "error";
    json["order"] = array;
    json["description"] = error.message;
    res.json(json);
  }
})
// 下面是组装查询，也可以总检，参数是stage:6/stageValue:1/status:6
app.post('/QueryUnionOrderByStatusStage', async (req, res) => {
  var body = req.body;
  var json = {};
  var array = new Array();
  var sql = "select union_order, status from machining_sheet where type_flag = '1'";
  var userInfo = CheckUserInfo(req);
  try
  {
    var index = 0;
    if( req.body.stage != undefined )
    {
      index = parseInt(req.body.stage);
      if( isNaN(index) )
        index = 5;
    }
    var status = 5;
    if( req.body.status != undefined )
    {
      status = parseInt(req.body.status);
      if( isNaN(status) )
        status = 5;
    }
    let suc2 = await db_util.query(sql);
    sql = "select * from machining_union_sheet";
    if( userInfo["isManager"] == false && index == 5 )
    {
      sql += " where engineer_zuzhuang like '%"+ userInfo["name"] +"%'";
    }
    sql += " ORDER by delivery_date ASC";
    console.log(sql + ', stage = ' + index + ', status = ' + status + ', ip = ' + req.ip + ', name = ' + userInfo["name"]);
    let sucData = await db_util.query(sql);
    if( suc2.length > 0 )
    {
      for(var k=0; k<sucData.length; k++)
      {
        sucData[k].tip = "";
        if( sucData[k].assemble_remark != '' )
          sucData[k].tip = "2";
      }
    }
    sql = "select * from machining_engineer where type = 'engineer_zuzhuang'";
    let suc1 = await db_util.query(sql);
    for(var j=0; j<sucData.length; j++)
    {
      if( req.body.stage != undefined )
      {
        if( sucData[j].stage.charAt(index) != '1' )
          continue;
      }
      var flag = false;
      for(var i=0; i<suc2.length; i++)
      {
        if( suc2[i].union_order != sucData[j].union_order )
          continue;
        if( suc2[i].status != status )
        {
          flag = true;
          break;
        }
      }
      if( flag == true )
        continue;

      // element.engineer的值需要从suc1中查找
      var engineer = "";
      for(var i=0; i<suc1.length; i++)
      {
        if( sucData[j].union_order == suc1[i].union_order )
        {
          if( engineer.length > 0 )
            engineer += ","
          engineer += suc1[i].name;
        }
      }
      sucData[j].engineer = engineer;
      
      array.push(sucData[j]);
    }
    // 主管加入已完成的记录
    if( body.job_no == undefined )
    {
      sql = "select * from machining_union_sheet where status = 1 OR stage = '0000000100'";
      sucData = await db_util.query(sql);
      sucData.forEach(element => {
        element["status"] = 1;
        array.push(element);
      });
    }
    json["result"] = "ok";
    json["count"] = array.length;
    json["order"] = array;
    res.status(200);
    res.json(json);
    //console.log('get result: ' + array.length);
  }
  catch(error)
  {
    console.log('QueryUnionOrder failed, ' + error.message);
    res.status(200);
    json["result"] = "error";
    json["order"] = array;
    json["errorCode"] = "2";
    json["description"] = error.message;
    res.json(json);
  }
})
app.post('/QueryWorkOrder', function(req, res) {
  var body = req.body;
  var sql = "select * from machining_sheet where union_order = '"+ body.unionorder +"'";
  if( body.cnc != undefined )
  {
    if( body.cnc.length > 0 && body.cnc != 'All' )
    {
      sql += " and cnc_name like '%"+ body.cnc +"%'";
    }
  }
  if( body.type != undefined )
  {
    sql += " and type_flag = '"+ body.type +"'";
  }
  if( body.box != undefined )
  {
    if( body.box.length > 0 )
      sql += " and box like '%"+ body.box +"%'";
  }
  if( body.status != undefined )
  {
    sql += " and status = '"+ body.status +"'";
    if( body.status == '4' ) // 二次加工，必须匹配指定的二次加工工程师
    {
      var userInfo = CheckUserInfo(req);
      if( userInfo["isManager"] == false )
      {
        sql += " and engineer_ercijiagong like '%"+ userInfo["name"] +"%'";
      }
    }
  }
  if( body.banci != undefined )
  {
    if( body.banci.length > 0 )
      sql += " and banci = '"+ body.banci +"'";
  }
  if( body.banci2 != undefined )
  {
    if( body.banci2.length > 0 )
      sql += " and banci2 = '"+ body.banci2 +"'";
  }
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      var json = {};
      var array = new Array();
      if( sucData.length > 0 )
      {
        sucData.forEach(element => {
            array.push(element);
        });
      }
      json["result"] = "ok";
      json["order"] = array;
      sql = "select * from machining_sheet where union_order = '"+ body.unionorder +"' and type_flag = '1'";
      db_util.ExecuteSQL(sql, null,
        (suc) =>
        {
          json["jiagongjian"] = suc.length;
          res.status(200);
          res.json(json);
        },
        (err) =>
        {
          res.status(200);
          res.json(json);
        }
      );
      //console.log('query result: ' + array.length);
    },
    (errData) =>
    {
      console.log(errData.message);
      res.status(200);
      json["result"] = "error";
      json["errorCode"] = "1";
      json["description"] = "not found the order";
      res.json(json);
    }
  );
})

app.post('/AddWorkTime',function(req,res){
  var body = req.body;
  var sql = "select total_time from machining_union_sheet where union_order='" + body.unionorder +"'";
  console.log('AddWorkTime ' + body.time + ' to ' + body.unionorder);
  if( body.time == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"time is null"});
    return;
  }
  db_util.ExecuteSQL(sql, null,
    (sucData) => 
    {
      if(sucData.length > 0)
      {
        var t = parseInt(sucData[0].total_time);
        if( isNaN(t) )
          t = 0;
        var t2 = 0;
        var index = body.time.indexOf(':');
        if( index > 0 )
        {
          sql = body.time.substr(0, index);
          t2 = parseInt(sql);
          var offset = index + 1;
          index = body.time.indexOf(':', offset);
          if( index > 0 )
          {
            t2 *= 3600;
            sql = body.time.substr(offset, index-offset);
            t2 += parseInt(sql) * 60;
            sql = body.time.substr(index+1);
            t2 += parseInt(sql);
          }
          else
          {
            t2 *= 60;
            sql = body.time.substr(offset);
            t2 += parseInt(sql);
          }
        }
        else
        {
          t2 = parseInt(body.time);
        }
        if( isNaN(t2) )
        {
          res.status(200);
          res.json({"result":"error", "description":"time is null"});
        }
        else
        {
          t += t2;
          sql = "Update machining_union_sheet set total_time = '"+ t +"' where union_order='" + body.unionorder +"'";
          db_util.ExecuteSQL(sql, null,
            (suc) => 
            {
              console.log('Succeeded: ' + sql);
              res.status(200);
              res.json({"result":"ok", "description":sucData.message});
            },
            (err) =>
            {
                res.status(200);
                res.json({"result":"error", "description":err.message});
                console.log('Failed: ' + sql);
            }
          );
        }
      }
      else
      {
        res.status(200);
        res.json({"result":"error", "description":"not find the order"});
      }
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "errorCode": "1", "description": errData.message});
      console.log(sql);
    }
  );
})

app.post('/UpdateUnionOrder',function(req,res){
  var body = req.body;
  var sql = "Update machining_union_sheet set ";
  sql += body.name;
  sql += " = '"+body.newValue+"' where union_order='" + body.unionorder +"'";
  if( body.name == "code19" )
  {
    if( body.newValue.length >= 19 )
    {
      var code1 = body.newValue.substr(0, 19);
      var code2 = code1.substr(0, 16);
      var sql2 = "select union_order, code19 from machining_union_sheet where code19 like '"+code2+"%' order by id desc";
      db_util.ExecuteSQL(sql2, null,
        (suc1) =>
        {
          var ok = true;
          var code3 = "";
          var order = "";
          for(var i=0; i<suc1.length; i++)
          {
            if( suc1[i].union_order == body.unionorder )
              continue;
            order = suc1[i].union_order;
            code3 = suc1[i].code19.substr(0, 19);
            if( suc1[i].code19.length > 38 )
              code3 = suc1[i].code19.substr(20);
            if( code1 <= code3 )
            {
              ok = false;
              break;
            }
          }
          if( ok == false )
          {
            console.log('Update code19 error, ' + order + ': ' + code3 + ' is bigger than ' + code1);
            res.status(200);
            res.json({"result":"error", "description":"", "code19":code3});
            return;
          }
          else
          {
            console.log(sql);
            db_util.ExecuteSQL(sql, null,
              (sucData) => 
              {
                //console.log(sucData.message);
                res.status(200);
                res.json({"result":"ok", "description":sucData.message});
              },
              (errData) =>
              {
                res.status(200);
                res.json({"result":"error", "errorCode": "1", "description": errData.message});
                console.log(sql);
              }
            );
          }
        },
        (err1) =>
        {
          console.log('query code19 failed, ' + err1.message);
          console.log(sql);
          db_util.ExecuteSQL(sql, null,
            (sucData) => 
            {
              //console.log(sucData.message);
              res.status(200);
              res.json({"result":"ok", "description":sucData.message});
            },
            (errData) =>
            {
              res.status(200);
              res.json({"result":"error", "errorCode": "1", "description": errData.message});
              console.log(sql);
            }
          );
        }
      );
    }
    else
    {
      console.log(sql);
      db_util.ExecuteSQL(sql, null,
        (sucData) => 
        {
          //console.log(sucData.message);
          res.status(200);
          res.json({"result":"ok", "description":sucData.message});
        },
        (errData) =>
        {
          res.status(200);
          res.json({"result":"error", "errorCode": "1", "description": errData.message});
          console.log(sql);
        }
      );
    }
  }
  else
  {
    console.log(sql);
    db_util.ExecuteSQL(sql, null,
      (sucData) => 
      {
        //console.log(sucData.message);
        res.status(200);
        res.json({"result":"ok", "description":sucData.message});
      },
      (errData) =>
      {
        res.status(200);
        res.json({"result":"error", "errorCode": "1", "description": errData.message});
        console.log(sql);
      }
    );
  }
})

app.post('/UpdateUnionOrder2', async (req, res) => {
  var body = req.body;
  var sql = "Update machining_union_sheet set ";
  try
  {
    sql += body.name1;
    if( body.name1 == 'engineer' || body.name1 == 'engineer_zuzhuang' )
    {
      var temp = "";
      for(var i=0; i<body.newValue1.length; i++)
      {
        if( i > 0 )
          temp += ",";
        temp += body.newValue1[i];
      }
      sql += " = '"+ temp +"'";
    }
    else if( body.name1 == 'stage' )
    {
      var index = parseInt(body.newValue1);
      if( isNaN(index) )
        index = 0;
      var sql2 = "select stage from machining_union_sheet where union_order = '"+ body.unionorder +"'";
      let suc = await db_util.query(sql2);
      var newValue = "";
      for(var i=0; i<index; i++)
      {
        newValue += suc[0].stage.charAt(i);
      }
      newValue += body.stageValue;
      if( body.newValue12 == undefined )
      {
        for(var i=index+1; i<suc[0].stage.length; i++)
        {
          newValue += suc[0].stage.charAt(i);
        }
      }
      else
      {
        var index2 = parseInt(body.newValue12);
        for(var i=index+1; i<index2; i++)
        {
          newValue += suc[0].stage.charAt(i);
        }
        newValue += body.stageValue2;
        for(var i=index2+1; i<suc[0].stage.length; i++)
        {
          newValue += suc[0].stage.charAt(i);
        }
      }
      sql += " = '"+ newValue +"'";
    }
    else
    {
      sql += " = '"+ body.newValue1 +"'";
    }
    if( body.name2 != undefined )
    {
      sql += ", ";
      sql += body.name2;
      sql += " = '"+ body.newValue2 +"'";
    }
    if( body.name3 != undefined )
    {
      sql += ", ";
      sql += body.name3;
      sql += " = '"+ body.newValue3 +"'";
    }
    if( body.name4 != undefined )
    {
      sql += ", ";
      sql += body.name4;
      sql += " = '"+ body.newValue4 +"'";
    }
    if( body.name5 != undefined )
    {
      sql += ", ";
      sql += body.name5;
      sql += " = '"+ body.newValue5 +"'";
    }
    if( body.name6 != undefined )
    {
      sql += ", ";
      sql += body.name6;
      sql += " = '"+ body.newValue6 +"'";
    }
    if( body.name7 != undefined )
    {
      sql += ", ";
      sql += body.name7;
      sql += " = '"+ body.newValue7 +"'";
    }
    if( body.name8 != undefined )
    {
      sql += ", ";
      sql += body.name8;
      sql += " = '"+ body.newValue8 +"'";
    }
    sql += " where union_order = '"+ body.unionorder +"'";
    console.log(sql);
    
    let sucData = await db_util.query(sql);
    if( body.name1 == 'engineer' || body.name1 == 'engineer_zuzhuang' )
    {
      sql = "delete from machining_engineer where union_order = '"+ body.unionorder +"' and type = '"+ body.name1 +"'";
      let suc1 = await db_util.query(sql);
      let suc2 = await db_util.query("select name, job_no from employee");
      var engineers = new Array(body.newValue1.length);
      for(var i=0; i<body.newValue1.length; i++)
      {
        var temp = new Array(5);
        temp[0] = body.unionorder;
        temp[1] = "";
        temp[2] = "";
        temp[3] = body.newValue1[i];
        temp[4] = body.name1;
        for(var n=0; n<suc2.length; n++)
        {
          if(suc2[n].name == body.newValue1[i])
          {
            temp[2] = suc2[n].job_no;
            break;
          }
        }
        engineers[i] = temp;
      }
      sql = "insert into machining_engineer values ?";
      let suc3 = await db_util.query(sql, [engineers]);
    }
    res.status(200);
    res.json({"result":"ok", "description":sucData.message});
  }
  catch(error)
  {
    res.status(200);
    res.json({"result":"error", "errorCode": "1", "description": error.message});
    console.log(sql);
  }
})

app.post('/UpdateWorkOrder', async (req, res) => {
  var body = req.body;
  if( body.unionorder == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"the unionorder is not set"});
    return;
  }
  else if( body.workorder == undefined )
  {
    if( body.status == undefined )
    {
      res.status(200);
      res.json({"result":"error", "description":"the workorder is not set"});
      return;
    }
  }
  var flag = false;
  var sql = "Update machining_sheet set ";
  if( body.remark != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "remark = '"+ body.remark +"'";
    flag = true;
  }
  if( body.cnc_name != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "cnc_name = '"+ body.cnc_name +"'";
    flag = true;
  }
  if( body.cnd_id != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "cnd_id = '"+ body.cnd_id +"'";
    flag = true;
  }
  if( body.status != undefined )
  {
    if(flag)
      sql += ", ";
    if( body.status2 != undefined )
      sql += "status = '"+ body.status2 +"'";
    else
      sql += "status = '"+ body.status +"'";
    flag = true;
  }
  if( body.designer != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "designer = '"+ body.designer +"'";
    flag = true;
  }
  if( body.jiagongriqi != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "jiagongriqi = '"+ body.jiagongriqi +"'";
    flag = true;
  }
  if( body.end_date != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "end_date = '"+ body.end_date +"'";
    flag = true;
  }
  if( body.speed_time != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "speed_time = '"+ body.speed_time +"'";
    flag = true;
  }
  if( body.estimate_time != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "estimate_time = '"+ body.estimate_time +"'";
    flag = true;
  }
  if( body.machine_remark != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "machine_remark = '"+ body.machine_remark +"'";
    flag = true;
  }
  if( body.box != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "box = '"+ body.box +"'";
    flag = true;
  }
  if( body.check_status != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "check_status = '"+ body.check_status +"'";
    flag = true;
  }
  if( body.check_tip != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "check_tip = '"+ body.check_tip +"'";
    flag = true;
  }
  if( body.check_remark != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "check_remark = '"+ body.check_remark +"'";
    flag = true;
  }
  if( body.check_date != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "check_date = '"+ body.check_date +"'";
    flag = true;
  }
  if( body.lingliao_riqi != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_riqi = '"+ body.lingliao_riqi +"'";
    flag = true;
  }
  if( body.lingliao_qixian != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_qixian = '"+ body.lingliao_qixian +"'";
    flag = true;
  }
  if( body.lingliao_bzhu != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_bzhu = '"+ body.lingliao_bzhu +"'";
    flag = true;
  }
  if( body.xuhao != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "xuhao = '"+ body.xuhao +"'";
    flag = true;
  }
  if( body.yibei_shuliang != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "yibei_shuliang = '"+ body.yibei_shuliang +"'";
    flag = true;
  }
  if( body.tuiku_shuliang != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "tuiku_shuliang = '"+ body.tuiku_shuliang +"'";
    flag = true;
  }
  if( body.banci != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "banci = '"+ body.banci +"'";
    flag = true;
  }
  if( body.banci2 != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "banci2 = '"+ body.banci2 +"'";
    flag = true;
  }
  if( body.beiliao_ztai != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "beiliao_ztai = '"+ body.beiliao_ztai +"'";
    flag = true;
  }
  if( body.bianchengriqi != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "bianchengriqi = '"+ body.bianchengriqi +"'";
    flag = true;
  }
  if( body.code_end_date != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "code_end_date = '"+ body.code_end_date +"'";
    flag = true;
  }
  if( body.code_time != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "code_time = '"+ body.code_time +"'";
    flag = true;
  }
  if( body.code_remark != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "code_remark = '"+ body.code_remark +"'";
    flag = true;
  }
  if( body.machine_end_date_2 != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "machine_end_date_2 = '"+ body.machine_end_date_2 +"'";
    flag = true;
  }
  if( body.machine_time_2 != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "machine_time_2 = '"+ body.machine_time_2 +"'";
    flag = true;
  }
  if( body.machine_remark_2 != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "machine_remark_2 = '"+ body.machine_remark_2 +"'";
    flag = true;
  }
  if( body.engineer_ercijiagong != undefined )
  {
    if( flag )
      sql += ", ";
    var temp = "";
    for(var i=0; i<body.engineer_ercijiagong.length; i++)
    {
      if( i > 0 )
        temp += ",";
      temp += body.engineer_ercijiagong[i];
    }
    sql += "engineer_ercijiagong = '"+ temp +"'";
    flag = true;
    if( body.workorder == undefined )
    {
      res.status(200);
      res.json({"result":"error", "description":"修改二次加工工程师必须指定加工单号：workorder"});
      return;
    }
  }
  if(flag)
  {
    sql += " where union_order = '"+ body.unionorder +"'";
    if( body.workorder != undefined )
      sql += " and sheet_order = '"+ body.workorder +"'";
    if( body.type != undefined )
      sql += " and type_flag = '"+ body.type +"'";
    if( body.status != undefined && body.status2 != undefined )
      sql += " and status = '"+ body.status +"'";
    console.log(sql);
    try
    {
      let sucData = await db_util.query(sql);
      var json = {};
      json["result"] = "ok";
      if( sucData.affectedRows > 0)
        json["description"] = "changedRows";
      else
        json["description"] = "not find the record";
      if( body.status != undefined )
      {
        // 原来的设计是，status=0：进行中；1/已完成；2/取消，但现在不是了，0/设计；1/编程；2/加工；3/品检；4/二次加工；5/组装；6/总检；7/入库
        /*if( body.status == '2' )
        {
          json["tip"] = "2";
        }
        else if( body.status == '0' )
        {
          sql = "select sheet_order from machining_sheet where union_order = '"+ body.unionorder +"' and status = '2'";
          let suc2 = await db_util.query(sql);
          if( suc2.length > 0 )
            json["tip"] = "2";
          else
            json["tip"] = "0";
        }*/
        
        sql = "update dispatch_sheet set status = '"+ body.status +"' where union_order = '"+ body.unionorder +"'";
        if( body.workorder != undefined )
          sql += " and ljmc='"+ body.workorder +"'";
        await db_util.query(sql);
        console.log('succeeded to execute: ' + sql);
        sql = "select id, status from dispatch_sheet where union_order = '"+ body.unionorder +"'";
        let suc5 = await db_util.query(sql);
        for(var k=0; k<suc5.length; k++)
        {
          if( suc5[k].status < body.status )
          {
            sql = "";
            break;
          }
        }
        if( sql.length > 0 ) // 所有加工件的状态都一致，说明该阶段已经结束了
        {
          var date = new Date();
          var endtime = getMonthDayTime(date, 1, 1);
          if( body.status == '2' )
            sql = "update machining_union_sheet set biancheng_endtime = '"+ endtime +"' where union_order = '"+ body.unionorder +"'";
          else if( body.status == '3' )
            sql = "update machining_union_sheet set jiagong_endtime = '"+ endtime +"' where union_order = '"+ body.unionorder +"'";
          else if( body.status == '5' )
            sql = "update machining_union_sheet set ercijg_endtime = '"+ endtime +"' where union_order = '"+ body.unionorder +"'";
          else if( body.status == '6' )
            sql = "update machining_union_sheet set zuzhuang_endtime = '"+ endtime +"' where union_order = '"+ body.unionorder +"'";
          else
            sql = "";
          if( sql.length > 0 )
            await db_util.query(sql);
        }
      }
      if( body.cnc_name != undefined )
      {
        sql = "update dispatch_sheet set cnc = '"+ body.cnc_name +"' where union_order='"+ body.unionorder +"' and ljmc='"+ body.workorder +"'";
        await db_util.query(sql);
        console.log('succeeded to update cnc in dispatch table');
      }
      if( body.engineer_ercijiagong != undefined )
      {
        sql = "delete from machining_engineer where union_order = '"+ body.unionorder +"' and sheet_order = '"+ body.workorder +"' and type = 'engineer_ercijiagong'";
        let suc1 = await db_util.query(sql);
        let suc2 = await db_util.query("select name, job_no from employee");
        var engineers = new Array();
        for(var i=0; i<body.engineer_ercijiagong.length; i++)
        {
          var temp = new Array(5);
          temp[0] = body.unionorder;
          temp[1] = body.workorder;
          temp[2] = "";
          temp[3] = body.engineer_ercijiagong[i];
          temp[4] = "engineer_ercijiagong";
          for(var n=0; n<suc2.length; n++)
          {
            if(suc2[n].name == body.engineer_ercijiagong[i])
            {
              temp[2] = suc2[n].job_no;
              break;
            }
          }
          engineers.push(temp);
        }
        if( engineers.length > 0 )
        {
          sql = "insert into machining_engineer values ?";
          let suc3 = await db_util.query(sql, [engineers]);
        }
      }
      res.status(200);
      res.json(json);
    }
    catch(error)
    {
      console.log('Failed: ' + sql);
      res.status(200);
      res.json({"result":"error", "description":error.message});
    }
  }
  else
  {
    res.status(200);
    res.json({"result":"error", "description":"no column was matched to update"});
    console.log('Failed: ' + sql);
  }
})

app.post('/DeleteUnionOrder',function(req,res){
  var body = req.body;
  var sql = "delete from machining_union_sheet where union_order = '" + body.unionorder + "'";
   db_util.ExecuteSQL(sql, null,
    (suc1) =>
    {
      sql = "delete from machining_sheet where union_order = '" + body.unionorder + "'";
      db_util.ExecuteSQL(sql, null,
        (suc2) => 
        {
          sql = "delete from dispatch_sheet where union_order = '" + body.unionorder + "'";
          db_util.ExecuteSQL(sql, null,
            (suc3) =>
            {
              sql = "select * from machining_files where union_order = '" + body.unionorder + "'";
              db_util.ExecuteSQL(sql, null,
                (suc4) =>
                {
                  suc4.forEach(element => {
                    fs.unlinkSync(element.file_path);
                  });
                  var path = "./public/" + body.unionorder;
                  fs.rmdir(path, (err6) => {
                    if(err)
                      console.log('failed to rmdir: ' + path);
                    else
                      console.log('succeeded to rmdir: ' + path);
                  });
                  sql = "delete from machining_files where union_order = '" + body.unionorder + "'";
                  db_util.ExecuteSQL(sql, null,
                    (suc5) =>
                    {
                      res.status(200);
                      res.json({"result":"ok"});
                    },
                    (err5) =>
                    {
                      res.status(200);
                      res.json({"result":"error", "errorCode": "5", "description": err5.message});
                    }
                  );
                },
                (err4) =>
                {
                  res.status(200);
                  res.json({"result":"error", "errorCode": "4", "description": err4.message});
                }
              );
            },
            (err3) =>
            {
              res.status(200);
              res.json({"result":"error", "errorCode": "3", "description": err3.message});
            }
          );
        },
        (err2) =>
        {
          console.log('Failed to delete union order: ' + body.unionorder);
          res.status(200);
          res.json({"result":"error", "errorCode": "2", "description": err2.message});
        }
      );
    },
    (err1) =>
    {
      res.status(200);
      res.json({"result":"error", "errorCode": "1", "description": err1.message});
    }
  );
})

app.post('/AddWorkOrder',function(req,res){
  var body = req.body;
  if(body.unionorder == undefined || body.workorder == undefined)
  {
    res.status(200);
    res.json({"result":"error", "errorCode": "1", "description": "not found the matched column"});
    return;
  }
  var sql = "select * from machining_sheet where union_order = '" + body.unionorder + "' and sheet_order = '"+ body.workorder +"'";
   db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      if( suc.length == 0 )
      {
        sql = "insert into machining_sheet (union_order, type, sheet_order, size_length, size_width, size_height, material_no, stuff, quatity, quatity_total) values('"+body.unionorder+ "', '"+body.type+"', '"+body.workorder+"', '"+body.length+"', '"+body.width+"', '"+body.height+"', '"+body.material_no+"', '"+body.stuff+"', '"+body.quatity+"', '"+body.quatity+"')";
        db_util.ExecuteSQL(sql, null,
          (sucData) => 
          {
            res.status(200);
            res.json({"result":"ok"});
          },
          (errData) =>
          {
            res.status(200);
            res.json(errData.message);
          }
        );
      }
      else
      {
        res.status(200);
        res.json({"result":"error", "errorCode": "1", "description": "the order exists already"});
      }
    },
    (err) =>
    {
      res.status(200),
      res.json({"result":"error", "errorCode": "1", "description": err.message}) ;
    }
  );
})

var g_cncInfo = null;
function loadCNC()
{
  if( g_cncInfo == null )
    g_cncInfo = new Array;
  db_util.ExecuteSQL("select * from cnc", null,
    (sucData) =>
    {
      if( sucData.length > 0 )
      {
        if( g_cncInfo.length > 0 )
          g_cncInfo.splice(0, g_cncInfo.length);
        sucData.forEach(element => {
          if( element.isRemoved == 0 )
            g_cncInfo.push(element);
        });
        for(var i=0; i<g_cncInfo.length; i++)
        {
          //g_cncInfo[i].reserved2 = 8;
          g_cncInfo[i]["lastmode"] = "";
          g_cncInfo[i]["lastmode_starttime"] = "";
          g_cncInfo[i]["lastmode_lasttime"] = "";
        }
        console.log("succeed to load cnc data, total " + g_cncInfo.length);
      }
      else
      {
        console.log("the table cnc is empty");
      }
    },
    (errData) =>
    {
      console.log("failed to query table cnc: " + errData.message);
    }
  );
}

function getcnc(stuff, length, width, quatity)
{
  var json = {};
  json["name"] = "";
  json["id"] = "";
  if( g_cncInfo == undefined )
     return json;
  if( g_cncInfo.length < 1 )
    return json;
  if( length[0] == 'D' || length[0] == 'd' )
  {
    var len = length.substr(1);
    for(var i=0; i<g_cncInfo.length; i++)
    {
      if(g_cncInfo[i].diameter_max < 1)
        continue;
      if(len <= g_cncInfo[i].diameter_max && width <= g_cncInfo[i].length_max)
      {
        json["name"] = g_cncInfo[i].name;
        json["id"] = g_cncInfo[i].id;
      }
      break;
    }
  }
  else
  {
    var len_min = 3000;
    var index = 100;
    for(var i=0; i<g_cncInfo.length; i++)
    {
      if(g_cncInfo[i].diameter_max > 0)
        continue;
      var temp = g_cncInfo[i].stuff_range;
      if( temp.length < 1)
      {
        for(var k=0; k<g_cncInfo.length; k++)
        {
          if(g_cncInfo[k].id == g_cncInfo[i].reserved1)
          {
            temp = g_cncInfo[k].stuff_range;
            break;
          }
        }
      }
      if( temp.indexOf(stuff) < 0)
        continue;
      if(length > g_cncInfo[i].length_max)
        continue;
      if(width > g_cncInfo[i].width_max)
        continue;
      if((g_cncInfo[i].length_max - length) < len_min)
      {
        len_min = g_cncInfo[i].length_max - length;
        index = i;
      }
    }
    if(index < g_cncInfo.length)
    {
      var arr = new Array;
      for(var k=0; k<g_cncInfo.length; k++)
      {
        if(g_cncInfo[k].length_max == g_cncInfo[index].length_max)
          arr.push(k);
      }
      if(arr.length > 1)
      {
        /*var k = Math.round(Math.random() * arr.length);
        if(k>=arr.length)
          k = arr.length - 1;
        index = arr[k];
        console.log("random: " + k);*/
        len_min = 3000;
        var newIndex = index;
        for(var k=0; k<arr.length; k++)
        {
          index = arr[k];
          if(g_cncInfo[index].loading < len_min)
          {
            len_min = g_cncInfo[index].loading;
            newIndex = index;
          }
        }
        index = newIndex;
      }
      g_cncInfo[index].loading = (parseInt(g_cncInfo[index].loading) + parseInt(quatity));
      json["name"] = g_cncInfo[index].name;
      json["id"] = g_cncInfo[index].id;
      json["loading"] = g_cncInfo[index].loading;
    }
  }
  return json;
}

function getdate(period)
{
  var days = new Array(31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365);
  var year = parseInt(period / 365);
  var day = parseInt(year * 365 + year/4);
  day = period - day;
  year += 1900;
  if( (year % 4) == 0 )
  {
    for(var i=1; i<12; i++)
      days[i] += 1;
  }
  var month = 1;
  if( day > 31 )
  {
    for(var i=10; i>=0; i--)
    {
      if( day > days[i])
      {
        month = i+2;
        day -= days[i];
        break;
      }
    }
  }
  var result = year;
  result += "-";
  if( month < 10 )
    result += "0";
  result += month;
  result += "-";
  if( day < 10 )
    result += "0";
  result += day;
  return result;
}

function getCNCOperatingMode(Model, mode)
{
  var ret = mode;
  if( Model == "FV102A" ) // Fanuc-a-4ax
  {
    if( mode == 3 )
      ret = "编辑模式";
    else if( mode == 2 )
      ret = "记忆模式";
    else if( mode == 0 )
      ret = "纸带模式";
  }
  else if( Model == "TMT-50" ) // Mitsubishi
  {
    if( mode == 99 )
      ret = "手轮";
    else if( mode == 1 )
      ret = "编辑";
    else if( mode == 2 )
      ret = "自动";
    else if( mode == 0 )
      ret = "寸动";
  }
  else if( Model == "Fanuc-0i MF" ) // Fanuc-Z
  {
    if( mode == 1 )
      ret = "编辑模式";
    else if( mode == 2 )
      ret = "记忆模式";
    else if( mode == 0 )
      ret = "纸带模式";
  }
  else
  {
    if( mode == 2 )
      ret = "自动";
    else if( mode == 0 )
      ret = "手动";
  }
  return ret;
}

function getCNCOperatingStatus(Model, status)
{
  var ret = status;
  if( Model == "FV102A" ) // Fanuc-a-4ax
  {
    if( status == 0 )
      ret = "待机";
    else if( status == 2 )
      ret = "运行";
  }
  else if( Model == "TMT-50" ) // Mitsubishi
  {
    if( status == 1 )
      ret = "待机";
    else if( status == 2 )
      ret = "运行";
    else if( status == 4 )
      ret = "报警";
  }
  else if( Model == "Fanuc-0i MF" ) // Fanuc-Z
  {
    if( status == 0 )
      ret = "待机";
    else if( status == 2 )
      ret = "运行";
  }
  else
  {
    if( status == 0 )
      ret = "手动";
    else if( status == 2 )
      ret = "自动";
    else if( status == 3 )
      ret = "报警";
  }
  return ret;
}

async function StatisticDetail(body_MachineName, body_starttime, body_endtime)
{
  var array = new Array();
  var arrIndex = {};
  var arrInfo = new Array();
  var MachineName = "";
  if( body_MachineName != undefined )
    MachineName = body_MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    var json = {};
    json["lastProgram"] = "";
    json["lastToolID"] = "";
    arrInfo.push(json);
    arrIndex[g_cncInfo[i].MachineName] = i;
  }
  var flag = false;
  var sql = "select * from cncdata";
  if( MachineName.length > 0 )
  {
    if( flag )
    {
      sql += " and MachineName = '"+ MachineName +"'";
    }
    else
    {
      flag = true;
      sql += " where MachineName = '"+ MachineName +"'";
    }
  }
  if( body_starttime != undefined )
  {
    if( flag )
    {
      sql += " and fmtTime >= '"+ body_starttime +"'";
    }
    else
    {
      flag = true;
      sql += " where fmtTime >= '"+ body_starttime +"'";
    }
  }
  if( body_endtime != undefined )
  {
    if( flag )
    {
      sql += " and fmtTime < '"+ body_endtime +"'";
    }
    else
    {
      flag = true;
      sql += " where fmtTime < '"+ body_endtime +"'";
    }
  }
  if( flag )
  {
    sql += " and length(program) > 0 and length(activetoolid) > 0";
  }
  else
  {
    flag = true;
    sql += " where length(program) > 0 and length(activetoolid) > 0";
  }
  sql += " ORDER BY Time ASC";
  console.log(sql);
  try
  {
    let suc = await db_util.query(sql);
    var index = -1;
    for(var k=0; k<suc.length; k++)
    {
      index = arrIndex[suc[k].MachineName];
      if( isNaN(index) )
        continue;
      if( suc[k].activetoolid == "0" )
        continue;
      if( arrInfo[index]["lastProgram"] == suc[k].program && arrInfo[index]["lastToolID"] == suc[k].activetoolid )
        continue;
      arrInfo[index]["lastProgram"] = suc[k].program;
      arrInfo[index]["lastToolID"] = suc[k].activetoolid;
      
      var json = {};
      json["MachineModel"] = g_cncInfo[index].MachineModel;
      json["MachineName"] = g_cncInfo[index].MachineName;
      json["status"] = suc[k].Operation_Mode;
      json["operatingmode"] = getCNCOperatingMode(json["MachineModel"], suc[k].operatingmode);
      json["operatingstatus"] = getCNCOperatingStatus(json["MachineModel"], suc[k].operatingstatus);
      json["feedrate"] = suc[k].feedrate;
      json["feedrateoverride"] = suc[k].feedrateoverride;
      json["actualspeed"] = suc[k].actualspeed;
      json["speedoverride"] = suc[k].speedoverride;
      json["program"] = suc[k].program;
      json["activetoolid"] = suc[k].activetoolid;
      json["cycletime"] = suc[k].cycletime;
      json["operatingtime"] = suc[k].operatingtime;
      var escapedTime = 0;
      var onTime = 0;
      if( suc.length > 1 )
      {
        var runTime = 0;
        var pcsTime = 0;
        var last_time = 0;
        for(var i=0; i<suc.length; i++)
        {
          if( suc[i].MachineName != json["MachineName"] )
            continue;
          if( suc[i].program != json["program"] )
            continue;
          if( suc[i].activetoolid != json["activetoolid"] )
            continue;
          
          if( suc[i].evt_type == "Run" )
            runTime = parseInt(suc[i].Time);
          else if( suc[i].evt_type == "Pcs" )
            pcsTime = parseInt(suc[i].Time);
          if( last_time > 0 && (suc[i].Time - last_time) < g_nOffTime )
          {
             onTime += (parseInt(suc[i].Time) - last_time);
          }
          last_time = parseInt(suc[i].Time);
        }
        if( runTime > 0 && pcsTime > 0 )
        {
          if( pcsTime > runTime )
            escapedTime = pcsTime - runTime;
          else
            escapedTime = runTime - pcsTime;
        }
        else
        {
          if( pcsTime > 0 ) // 只有结束时间，没有开始时间
            escapedTime = 1;
          else if( runTime > 0 )
            onTime = last_time - runTime;
        }
      }
      if( escapedTime >= 120*1000 || (escapedTime == 0 && onTime > 0) )
      {
        if( escapedTime >= 120*1000 )
          onTime = escapedTime;
        onTime = parseInt(onTime/1000);
        var h = parseInt(onTime/3600);
        var m = parseInt((onTime - h*3600)/60);
        var s = onTime - h*3600 - m*60;
        if( h < 10 )
          suc[k].cycletime = "0";
        suc[k].cycletime += h;
        suc[k].cycletime += ":";
        if( m < 10 )
          suc[k].cycletime += "0";
        suc[k].cycletime += m;
        suc[k].cycletime += ":";
        if( s < 10 )
          suc[k].cycletime += "0";
        suc[k].cycletime += s;
        json["cycletime"] = suc[k].cycletime;
        array.push(json);
      }
    }
  }
  catch(err)
  {
    console.log('StatisticDetail error: ' + err.message);
  }
  return array;
}

app.post('/QueryCncDetail', async (req, res) => {
  var date = new Date();
  console.log('QueryCncDetail from ' + req.ip + ' on ' + getMonthDayTime(date, 1, 1)); 
  if( req.body.starttime == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set a parameter of starttime"});
    return;
  }
  let array = await StatisticDetail(req.body.MachineName, req.body.starttime, req.body.endtime);
  res.status(200);
  res.json({"result":"ok","order":array});
})

app.post('/QueryCncInfo', async (req, res) => {
  var date = new Date();
  //console.log('QueryCncInfo from ' + req.ip + ' on ' + date.toLocaleString()); 
  var array = new Array();
  if( g_cncInfo == undefined )
  {
    res.status(200);
    res.json({"result":"ok","order":array});
    return;
  }
  var MachineName = "";
  if( req.body.MachineName != undefined )
    MachineName = req.body.MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["id"] = g_cncInfo[i].id;
    json["name"] = g_cncInfo[i].name;
    json["MachineName"] = g_cncInfo[i].MachineName;
    json["MachineModel"] = g_cncInfo[i].MachineModel;
    json["MachineSN"] = g_cncInfo[i].MachineSN;
    if( req.body.status == undefined )
    {
      json["diameter_max"] = g_cncInfo[i].diameter_max;
      json["length_max"] = g_cncInfo[i].length_max;
      json["width_max"] = g_cncInfo[i].width_max;
      json["stuff_type"] = g_cncInfo[i].stuff_type;
      if( g_cncInfo[i].stuff_range.length > 0 )
      {
        json["stuff_range"] = g_cncInfo[i].stuff_range;
      }
      else
      {
        var k = i - 1;
        while( k >= 0 )
        {
          if( g_cncInfo[k].stuff_range.length > 0 )
          {
            json["stuff_range"] = g_cncInfo[k].stuff_range;
            break;
          }
          else
            k -= 1;
        }
      }
    }
    else if( req.body.status != "Alarm" )
    {
      json["status"] = "OFF";
    }
    array.push(json);
  }
  if( req.body.status == undefined )
  {
    var sql = "select * from cnc where isRemoved != 0";
    let suc = await db_util.query(sql);
    for(var i=0; i<suc.length; i++)
    {
      var json = {};
      json["id"] = suc[i].id;
      json["name"] = suc[i].name;
      json["MachineName"] = suc[i].MachineName;
      json["MachineModel"] = suc[i].MachineModel;
      json["MachineSN"] = suc[i].MachineSN;
      json["diameter_max"] = suc[i].diameter_max;
      json["length_max"] = suc[i].length_max;
      json["width_max"] = suc[i].width_max;
      json["stuff_type"] = suc[i].stuff_type;
      json["stuff_range"] = suc[i].stuff_range;
      json["status"] = "OFF";
      array.push(json);
    }
    res.status(200);
    res.json({"result":"ok","order":array});
    return;
  }
  if( req.body.status.length > 0 )
    console.log('QueryCncInfo ' + req.body.status);
  if( req.body.status == "Alarm" )
  {
    var sql = "select MachineName, Time, fmtTime, alarmstatus from cncdata where alarmstatus != 'False' and alarmstatus != 'True'";
    if( MachineName.length > 0 )
      sql += " and MachineName = '"+ MachineName +"'";
    if( req.body.starttime != undefined )
      sql += " and fmtTime >= '"+ req.body.starttime +"'";
    if( req.body.endtime != undefined )
      sql += " and fmtTime < '"+ req.body.endtime +"'";
    sql += " ORDER BY Time ASC";
    console.log(sql);
    try
    {
      let suc = await db_util.query(sql);
      for(var i=0; i<array.length; i++)
      {
        var alarms = new Array();
        var last_time = "";
        var last_alarm = "";
        var flag = false;
        for(var k=0; k<suc.length; k++)
        {
          if( array[i].MachineName == suc[k].MachineName )
          {
            if( suc[k].alarmstatus.length > 0 )
            {
              flag = false;
              if( last_alarm != suc[k].alarmstatus )
              {
                flag = true;
              }
              else if( (suc[k].Time - last_time) > 60000 )
              {
                flag = true;
              }
              if( flag == true )
              {
                var json = {};
                json["time"] = suc[k].fmtTime;
                json["alarm"] = suc[k].alarmstatus;
                alarms.push(json);
              }
              last_time = suc[k].Time;
              last_alarm = suc[k].alarmstatus;
            }
          }
        }
        array[i]["alarms"] = alarms;
      }
      res.status(200);
      res.json({"result":"ok","order":array});
      return;
    }
    catch(error)
    {
      console.log('QueryCncInfo - Alarm error: ' + error.message);
      var alarms = new Array();
      res.status(200);
      res.json({"result":"error","order":array,"description":err.message});
      return;
    }
  }
  else if( req.body.status == "WorkTime" )
  {
    var array = new Array();
    var MachineName = "";
    if( req.body.MachineName != undefined )
      MachineName = req.body.MachineName;
    var flag = false;
    var condition = "";
    if( req.body.starttime != undefined )
    {
      if( flag )
      {
        condition += " and fmtTime >= '"+ req.body.starttime +"'";
      }
      else
      {
        flag = true;
        condition += " where fmtTime >= '"+ req.body.starttime +"'";
      }
    }
    if( req.body.endtime != undefined )
    {
      if( flag )
      {
        condition += " and fmtTime < '"+ req.body.endtime +"'";
      }
      else
      {
        flag = true;
        condition += " where fmtTime < '"+ req.body.endtime +"'";
      }
    }
    if( flag )
    {
      condition += " and length(program) > 0 and length(activetoolid) > 0";
    }
    else
    {
      flag = true;
      condition += " where length(program) > 0 and length(activetoolid) > 0";
    }
    sql += " ORDER BY Time ASC";
    try
    {
      var sql = "select MachineName, program, activetoolid from cncdata" + condition;
      if( MachineName.length > 0 )
        sql += " and MachineName = '"+ MachineName +"'";
      sql += " GROUP BY program ORDER BY Time ASC";
      let suc = await db_util.query(sql);
      var starttime = 0;
      var endtime = 0;
      var date = new Date();
      for(var i=0; i<suc.length; i++)
      {
        if( suc[i].activetoolid == "0" )
          continue;
        sql = "select evt_type, Time, program, activetoolid from cncdata";
        sql += condition;
        sql += " and MachineName = '"+ suc[i].MachineName +"'";
        sql += " and program = '"+ suc[i].program +"'";
        sql += " ORDER BY id ASC";
        let suc2 = await db_util.query(sql);
        starttime = 0;
        endtime = 0;
        for(var k=0; k<suc2.length; k++)
        {
          if( suc2[k].activetoolid == "0" )
            continue;
          if( suc2[k].evt_type == "Run" ) // 开始
            starttime = parseInt(suc2[k].Time);
          else if( suc2[k].evt_type == "Pcs" )
            endtime = parseInt(suc2[k].Time);
          if( starttime > 0 && endtime > 0 )
            break;
        }
        if( starttime == 0 || endtime == 0 || starttime >= endtime )
        {
          starttime = 0;
          endtime = 0;
        }
        if( starttime == 0 )
          starttime = parseInt(suc2[0].Time);
        if( endtime == 0 )
          endtime = parseInt(suc2[suc2.length-1].Time);
        var json = {};
        date.setTime(starttime);
        json["MachineName"] = suc[i].MachineName;
        json["starttime"] = getMonthDayTime(date, 1, 1);
        json["program"] = suc[i].program;
        endtime = parseInt((endtime - starttime)/1000);
        starttime = parseInt(endtime/3600);
        if( starttime < 9 )
          sql = '0' + starttime + ':';
        else
          sql = starttime + ':';
        endtime -= (starttime * 3600);
        starttime = parseInt(endtime/60);
        if( starttime < 9 )
          sql += ('0' + starttime + ':');
        else
          sql += (starttime + ':');
        endtime -= (starttime * 60);
         if( endtime < 9 )
          sql += ('0' + endtime);
        else
          sql += endtime;
        json["operatingtime"] = sql;
        array.push(json);
      }
      res.status(200);
      res.json({"result":"ok","order":array});
      return;
    }
    catch(error)
    {
      console.log('查询加工总时间 error: ' + error.message);
      var alarms = new Array();
      res.status(200);
      res.json({"result":"error","order":array,"description":error.message});
      return;
    }
  }
  else
  {
    var sql = "select * from cncdata";
    if( MachineName.length > 0 )
      sql += " where MachineName = '"+ MachineName +"' order by id desc limit 2";
    else
      sql += " order by id desc limit " + 3 * g_cncInfo.length;
    //console.log(sql);
    try
    {
      let suc = await db_util.query(sql);
      let suc4 = await db_util.query("select sheet_order, file_path from machining_files where union_order = 'kanban' ORDER BY id DESC");
      for(var i=0; i<array.length; i++)
      {
        array[i]["url"] = "";
        for(var k=0; k<suc4.length; k++)
        {
          if( suc4[k].sheet_order == array[i].MachineName )
          {
            array[i]["url"] = suc4[k].file_path;
            break;
          }
        }
      }
      // 查询设备当前状态
      var currTime = Date.now() - g_nWaitTime;
      {
        //var ct = new Date(currTime);
        //var st = new Date(parseInt(suc[0].Time));
        //console.log('前3分钟时间：' + ct.toLocaleString() + '，数据最新时间：' + st.toLocaleString());
      }
      if( g_lastUpdateTime > currTime )
      {
        for(var i=0; i<array.length; i++)
        {
          for(var k=0; k<suc.length; k++)
          {
            if( array[i].MachineName == suc[k].MachineName )
            {
              array[i].status = suc[k].Operation_Mode;
              array[i]["operatingmode"] = getCNCOperatingMode(array[i].MachineModel, suc[k].operatingmode);
              array[i]["operatingstatus"] = getCNCOperatingStatus(array[i].MachineModel, suc[k].operatingstatus);
              array[i]["cycletime"] = suc[k].cycletime;
              array[i]["operatingtime"] = suc[k].operatingtime;
              array[i]["partcount"] = suc[k].partcount;
              array[i]["feedrate"] = suc[k].feedrate;
              array[i]["feedrateoverride"] = suc[k].feedrateoverride;
              array[i]["program"] = suc[k].program;
              array[i]["actualspeed"] = suc[k].actualspeed;
              array[i]["speedoverride"] = suc[k].speedoverride;
              array[i]["activetoolid"] = suc[k].activetoolid;
              array[i]["union_order"] = "";
              if( g_cncInfo[i]["lastmode_starttime"] == "" )
              {
                array[i]["status_starttime"] = "";
              }
              else
              {
                var date = new Date(parseInt(g_cncInfo[i]["lastmode_starttime"]));
                array[i]["status_starttime"] = getMonthDayTime(date, 1, 1);
              }
              break;
            }
          }
        }
        if( array.length == 1 && array[0]["program"].length > 0 )
        {
          sql = "select union_order from dispatch_sheet where cxmc = '"+ array[0]["program"] +"'";
          console.log(sql);
          let suc2 = await db_util.query(sql);
          if( suc2.length > 0 )
            array[0]["union_order"] = suc2[0].union_order;
          res.status(200);
          res.json({"result":"ok","order":array});
          return;
        }
        else
        {
          res.status(200);
          res.json({"result":"ok","order":array});
          return;
        }
      }
      else
      {
        for(var i=0; i<array.length; i++)
        {
          for(var k=0; k<suc.length; k++)
          {
            if( array[i].MachineName == suc[k].MachineName )
            {
              array[i]["status"] = "OFF";
              array[i]["status_starttime"] = suc[k].fmtTime;
              break;
            }
          }
        }
        res.status(200);
        res.json({"result":"ok","order":array});
        return;
      }
    }
    catch(error)
    {
      res.status(200);
      var alarms = new Array();
      res.json({"result":"ok","order":array,"description":error.message});
      return;
    }
  }
})

async function StatisticUtilization(body_MachineName, body_starttime, body_endtime, body_mode) // 稼动率统计
{
  var flag = false;
  var MachineName = "";
  if( body_MachineName != undefined )
    MachineName = body_MachineName;
  //var date = new Date();
  var temp = new Array(); // 返回值
  var array = new Array();
  var arrIndex = {};
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["name"] = g_cncInfo[i].name;
    json["MachineName"] = g_cncInfo[i].MachineName;
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    json["idle_time"] = 0;
    json["idle_start"] = 0;
    json["idle_end"] = 0;
    json["idle_count"] = 0;
    json["shutdown_time"] = 0;
    json["shutdown_start"] = 0;
    json["shutdown_end"] = 0;
    json["shutdown_count"] = 0;
    json["off_time"] = 0;
    json["off_start"] = 0;
    json["off_end"] = 0;
    json["off_count"] = 0;
    json["lastID"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }
  var sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  if( body_starttime != undefined )
  {
    if( body_starttime < '2020-06-01 08:00:00' )
    {
      console.log('StatisticUtilization starttime error: ' + body_starttime);
      array = null;
      return temp;
    }
    if( flag )
    {
      sql += " and fmtTime >= '"+ body_starttime +"'";
    }
    else
    {
      flag = true;
      sql += " where fmtTime >= '"+ body_starttime +"'";
    }
  }
  else // 如果没有设置开始时间，那就统计所有数据
  {
    try
    {
      let suc2 = await db_util.query("select * from cncstat");
      for(var k=0; k<suc2.length; k++) // 添加新的统计数据
      {
        if( k == 0 )
        {
          if( flag )
          {
            sql += " and id > '"+ suc2[0].lastID +"'";
          }
          else
          {
            flag = true;
            sql += " where id > '"+ suc2[0].lastID +"'";
          }
        }
        for(var i=0; i<array.length; i++)
        {
          if( array[i].MachineName == suc2[k].MachineName )
          {
            array[k]["last_mode"] = suc2[i].lastMode;
            array[k]["last_time"] = suc2[i].lastMode_starttime;
            array[i]["run_time"] += suc2[k].run_time * 1000;
            array[i]["idle_time"] += suc2[k].idle_time * 1000;
            array[i]["idle_count"] += suc2[k].idle_count;
            array[i]["shutdown_time"] += suc2[k].shutdown_time * 1000;
            array[i]["shutdown_count"] += suc2[k].shutdown_count;
            array[i]["off_time"] += suc2[k].off_time * 1000;
            array[i]["off_count"] += suc2[k].off_count;
            array[i]["lastID"] = suc2[k].lastID;
            if( array[k]["last_mode"] == "Run" )
              array[i]["run_start"] = array[k]["last_time"];
            else if( array[k]["last_mode"] == "Idle" )
              array[i]["idle_start"] = array[k]["last_time"];
            else if( array[k]["last_mode"] == "Shutdown" )
              array[i]["shutdown_start"] = array[k]["last_time"];
            else if( array[k]["last_mode"] == "OFF" )
              array[i]["off_start"] = array[k]["last_time"];
            break;
          }
        }
      }
    }
    catch(error)
    {
      console.log('StatisticUlitization: cncstat, ' + error.message);
    }
  }
  if( body_endtime != undefined )
  {
    if( flag )
    {
      sql += " and fmtTime < '"+ body_endtime +"'";
    }
    else
    {
      flag = true;
      sql += " where fmtTime < '"+ body_endtime +"'";
    }
  }
  if( MachineName.length > 0 )
  {
    if( flag )
    {
      sql += " and MachineName = '"+ MachineName +"'";
    }
    else
    {
      flag = true;
      sql += " where MachineName = '"+ MachineName +"'";
    }
  }
  sql += " ORDER BY Time ASC";
  console.log('统计稼动率：' + sql.substr(64));
  try
  {
    let suc = await db_util.query(sql);
    var index = -1;
    var currentTime = 0;
    for(var k=0; k<suc.length; k++)
    {
      index = arrIndex[suc[k].MachineName];
      if( isNaN(index) )
        continue;
      currentTime = parseInt(suc[k].Time);
      if( array[index]["start_time"] == 0 )
        array[index]["start_time"] = currentTime;
      // 判断是否有关机过程
      if( array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime ) // 间隔时间大于10分钟
      {
        //console.log(suc[k].MachineName + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
        array[index]["off_time"] += (currentTime - array[index]["last_time"]);
        array[index]["off_count"] ++;

        if( array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0 )
        {
          array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
        }
        if( array[index]["last_mode"] == "Idle" && array[index]["idle_start"] > 0 )
        {
          array[index]["idle_time"] += (array[index]["last_time"] - array[index]["idle_start"]);
        }
        if( array[index]["last_mode"] == "Shutdown" && array[index]["shutdown_start"] > 0 )
        {
          array[index]["shutdown_time"] += (array[index]["last_time"] - array[index]["shutdown_start"]);
        }
        if( array[index]["last_mode"] == "OFF" && array[index]["off_start"] > 0 )
        {
          array[index]["off_time"] += (array[index]["last_time"] - array[index]["off_start"]);
        }
        array[index]["run_start"] = 0;
        array[index]["idle_start"] = 0;
        array[index]["shutdown_start"] = 0;
        array[index]["off_start"] = 0;
        array[index]["last_time"] = 0;
      }
      if( k == 0 && array[index]["last_time"] > 0 )
      {
        var tempTime = currentTime;
        currentTime = array[index]["last_time"]; // 计算的时候避免这两个值之间的差漏算了
        array[index]["last_time"] = tempTime;
      }
      else
      {
        array[index]["last_time"] = currentTime;
      }
      array[index]["last_mode"] = suc[k].Operation_Mode;
      array[index]["lastID"] = parseInt(suc[k].id);

      // 计算运行时间
      array[index]["run_end"] = currentTime;
      if( suc[k].Operation_Mode == "Run" )
      {
        if( array[index]["run_start"] == 0 )
          array[index]["run_start"] = currentTime;
      }
      else if( array[index]["run_start"] > 0 )
      {
        array[index]["run_time"] += (array[index]["run_end"] - array[index]["run_start"]);
        array[index]["run_start"] = 0;
        array[index]["run_end"] = 0;
      }
      // 计算等待时间
      array[index]["idle_end"] = currentTime;
      if( suc[k].Operation_Mode == "Idle" )
      {
        if( array[index]["idle_start"] == 0 )
        {
          array[index]["idle_start"] = currentTime;
          array[index]["idle_count"] ++;
        }
      }
      else if( array[index]["idle_start"] > 0 )
      {
        array[index]["idle_time"] += (array[index]["idle_end"] - array[index]["idle_start"]);
        array[index]["idle_start"] = 0;
        array[index]["idle_end"] = 0;
      }
      // 计算停机时间
      array[index]["shutdown_end"] = currentTime;
      if( suc[k].Operation_Mode == "Shutdown" )
      {
        if( array[index]["shutdown_start"] == 0 )
        {
          array[index]["shutdown_start"] = currentTime;
          array[index]["shutdown_count"] ++;
        }
      }
      else if( array[index]["shutdown_start"] > 0 )
      {
        array[index]["shutdown_time"] += (array[index]["shutdown_end"] - array[index]["shutdown_start"]);
        array[index]["shutdown_start"] = 0;
        array[index]["shutdown_end"] = 0;
      }
      // 计算关机时间
      array[index]["off_end"] = currentTime;
      if( suc[k].Operation_Mode == "OFF" )
      {
        if( array[index]["off_start"] == 0 )
        {
          array[index]["off_start"] = currentTime;
          array[index]["off_count"] ++;
        }
      }
      else if( array[index]["off_start"] > 0 )
      {
        array[index]["off_time"] += (array[index]["off_end"] - array[index]["off_start"]);
        array[index]["off_start"] = 0;
        array[index]["off_end"] = 0;
      }
    }
    for(index=0; index<array.length; index++)
    {
      if( array[index]["run_start"] > 0 && array[index]["run_end"] > array[index]["run_start"] )
        array[index]["run_time"] += (array[index]["run_end"] - array[index]["run_start"]);
      if( array[index]["idle_start"] > 0 && array[index]["idle_end"] > array[index]["idle_start"] )
        array[index]["idle_time"] += (array[index]["idle_end"] - array[index]["idle_start"]);
      if( array[index]["shutdown_start"] > 0 && array[index]["shutdown_end"] > array[index]["shutdown_start"] )
        array[index]["shutdown_time"] += (array[index]["shutdown_end"] - array[index]["shutdown_start"]);
      if( array[index]["off_start"] > 0 && array[index]["off_end"] > array[index]["off_start"] )
        array[index]["off_time"] += (array[index]["off_end"] - array[index]["off_start"]);
    }
    /* 不必重新计算 2020/08/10
    // 重新计算关机时间：总时间 - 运行时间 - 等待时间 - 故障时间
    var starttime = 0;
    var endtime = 0;
    if( body_starttime != undefined )
      starttime = Date.parse(body_starttime);
    if( suc.length > 0 )
      starttime = parseInt(suc[0].Time);
    if( body_endtime != undefined )
      endtime = Date.parse(body_endtime);
    if( suc.length > 1 )
      endtime = parseInt(suc[suc.length-1].Time);
    for(var i=0; i<array.length; i++)
    {
      currentTime = (endtime - starttime) - array[i]["run_time"] - array[i]["idle_time"] - array[i]["shutdown_time"];
      if( currentTime > array[i]["off_time"] )
        array[i]["off_time"] = currentTime;
    }*/
    for(var i=0; i<array.length; i++)
    {
      var json = {};
      json["name"] = array[i]["name"];
      json["MachineName"] = array[i]["MachineName"];
      json["run_time"] = array[i]["run_time"];
      json["total_time"] = array[i]["last_time"] - array[i]["start_time"]; //endtime - starttime;
      json["idle_time"] = array[i]["idle_time"];
      json["idle_count"] = array[i]["idle_count"];
      json["shutdown_time"] = array[i]["shutdown_time"];
      json["shutdown_count"] = array[i]["shutdown_count"];
      json["off_time"] = array[i]["off_time"];
      json["off_count"] = array[i]["off_count"];
      json["last_mode"] = array[i]["last_mode"];
      json["last_time"] = array[i]["last_time"];
      json["start_time"] = array[i]["start_time"];
      if( suc.length > 0 )
        json["lastID"] = suc[suc.length-1].id;
      else
        json["lastID"] = array[i]["lastID"];
      json["last_id"] = array[i]["lastID"];
      temp.push(json);
      //console.log(json["MachineName"] + '运行时间' + json["run_time"] + '，关机时间' + json["off_time"] + '，总时长' + json["total_time"]);
    }

    if( body_starttime == undefined && suc.length > 0 ) // 查询某个时间段就不用去更新表cncstat了
    {
      for(var i=0; i<array.length; i++)
      {
        array[i]["lastID"] = suc[suc.length-1].id;
        array[i]["run_time"] = parseInt(array[i]["run_time"]/1000 + 0.5);
        array[i]["idle_time"] = parseInt(array[i]["idle_time"]/1000 + 0.5);
        array[i]["shutdown_time"] = parseInt(array[i]["shutdown_time"]/1000 + 0.5);
        array[i]["off_time"] = parseInt(array[i]["off_time"]/1000 + 0.5);

        var sql = "select * from cncstat where MachineName = '"+ array[i]["MachineName"] +"'";
        let row = await db_util.query(sql);
        if( row.length == 0 )
        {
          sql = "insert into cncstat values('"+ array[i]["MachineName"] +"', '"+ array[i]["last_mode"] +"', ";
          sql += "'"+ array[i]["last_time"] +"', '"+ array[i]["lastID"] +"', '"+ array[i]["run_time"] +"', ";
          sql += "'"+ array[i]["idle_time"] +"', '"+ array[i]["idle_count"] +"', ";
          sql += "'"+ array[i]["shutdown_time"] +"', '"+ array[i]["shutdown_count"] +"', ";
          sql += "'"+ array[i]["off_time"] +"', '"+ array[i]["off_count"] +"')";
          await db_util.query(sql);
        }
        else
        {
          sql = "update cncstat set lastMode = '"+ array[i]["last_mode"] +"', lastMode_starttime = '"+ array[i]["last_time"] +"', ";
          sql += "lastID = '"+ array[i]["lastID"] +"', run_time = '"+ array[i]["run_time"] +"', "
          sql += "idle_time = '"+ array[i]["idle_time"] +"', idle_count = '"+ array[i]["idle_count"] +"', ";
          sql += "shutdown_time = '"+ array[i]["shutdown_time"] +"', shutdown_count = '"+ array[i]["shutdown_count"] +"', ";
          sql += "off_time = '"+ array[i]["off_time"] +"', off_count = '"+ array[i]["off_count"] +"' ";
          sql += "where MachineName = '"+ array[i]["MachineName"] +"'";
          await db_util.query(sql);
        }
      }
    }
    array = null;
    return temp;
  }
  catch(error)
  {
    console.log('StatisticUtilization exception: ' + error.message);
    array = null;
    return temp;
  }
}

app.post('/QueryCncTime', async (req, res) => {
  if( req.body.starttime != undefined )
  {
    if( req.body.starttime < '2020-06-01 08:00:00' )
    {
      //console.log('QueryCncTime starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  var date = new Date();
  var cost_time = date.getTime();
  //console.log('QueryCncTime from ' + req.ip + ' on ' + date.toLocaleString()); 
  var array = new Array();
  var arrIndex = {};
  var MachineName = "";
  //if( req.body.MachineName != undefined )
  //  MachineName = req.body.MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["id"] = g_cncInfo[i].id;
    json["name"] = g_cncInfo[i].name;
    json["MachineName"] = g_cncInfo[i].MachineName;
    json["MachineModel"] = g_cncInfo[i].MachineModel;
    json["MachineSN"] = g_cncInfo[i].MachineSN;
    json["run_time"] = 0;
    json["idle_time"] = 0;
    json["shutdown_time"] = 0;
    json["off_time"] = 0;
    json["total_time"] = 0;
    json["last_time"] = 0;
    json["last_mode"] = "";
    json["last_id"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }

  var starttime = 0;
  var month_jiadonglv = false;
  if( req.body.mode != "hour" )
  {
    date.setTime(Date.parse(req.body.starttime));
    if( date.getDate() == 1 && date.getHours() == 0 ) // 获取当月稼动率时才用
    {
      month_jiadonglv = true;
      var month = getMonthDayTime(date);
      var sql = "select * from currentmonth where month = '"+ month +"'";
      let suc2 = await db_util.query(sql);
      for(var i=0; i<suc2.length; i++)
      {
        var index = arrIndex[suc2[i].MachineName];
        if( isNaN(index) ) // total
        {
          starttime = parseInt(suc2[i].last_time);
          continue;
        }
        array[index]["run_time"] = parseInt(suc2[i].run_time);
        array[index]["idle_time"] = parseInt(suc2[i].idle_time);
        array[index]["shutdown_time"] = parseInt(suc2[i].shutdown_time);
        array[index]["off_time"] = parseInt(suc2[i].off_time);
        array[index]["total_time"] = parseInt(suc2[i].total_time);
        array[index]["last_time"] = parseInt(suc2[i].last_time);
        array[index]["last_mode"] = suc2[i].last_mode;
        array[index]["last_id"] = parseInt(suc2[i].last_id);
        if( starttime < array[index]["last_time"] )
          starttime = array[index]["last_time"];
      }
      suc2 = null;
    }
  }

  var sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  var msg = "QueryCncTime starttime = " + req.body.starttime;
  if( starttime > 0 )
    sql += " where Time >= '"+ starttime +"'";
  else
    sql += " where fmtTime >= '"+ req.body.starttime +"'";
  if( req.body.endtime != undefined )
  {
    msg += ", endtime = " + req.body.endtime;
    sql += " and fmtTime < '"+ req.body.endtime +"'";
  }
  if( MachineName.length > 0 )
  {
    msg += ", cnc = " + MachineName;
    sql += " and MachineName = '"+ MachineName +"'";
  }
  if( req.body.lastID != undefined )
  {
    sql += " and id <= '"+ req.body.lastID +"'";
  }
  if( req.body.mode != undefined )
  {
    msg += ", mode = " + req.body.mode;
  }
  sql += " ORDER BY Time ASC";
  if( month_jiadonglv == true && msg.length > 0 )
  {
    date.setTime(cost_time);
    console.log(msg + ' on ' + getMonthDayTime(date, 1, 1) + ' from ' + req.ip);
  }
  //console.log('QueryCncTime: ' + sql.substr(64) + ' on ' + cost_time);
  try
  {
    let suc = await db_util.query(sql);
    var update = false;
    var endtime = 0;
    var spantime = 0;
    if( req.body.starttime != undefined )
    {
      if( starttime == 0 )
        starttime = Date.parse(req.body.starttime);
    }
    else if( suc.length > 0 )
    {
      starttime = parseInt(suc[0].Time);
    }
    if( req.body.endtime != undefined  )
    {
      endtime = Date.parse(req.body.endtime);
    }
    else if( suc.length > 0 )
    {
      endtime = parseInt(suc[suc.length-1].Time);
    }
    else
    {
      endtime = Date.now();
    }
    if( month_jiadonglv == true && suc.length > 0 )
    {
      spantime = await CalcHolidayTime(Date.parse(req.body.starttime), endtime, null, 1);
      if( suc.length > 1 )
        console.log('当月稼动率统计新增记录条数：' + suc.length + '，最新ID：' + suc[suc.length-1].id + '，周日及假期：' + (spantime/3600000) + '小时/台');
      else
        console.log('当月稼动率统计，最新ID：' + suc[suc.length-1].id + '，周日及假期：' + (spantime/3600000) + '小时/台');
    }

    var flag = false;
    if( req.body.mode == "hour" )
    {
      flag = true; // 按小时分段计算
      if( (endtime - starttime) < 3600001 ) // 只有一个小时，取消
        flag = false;
      else if( suc.length == 0 )
        flag = false;
    }
    var total_run_time = 0; // 单位是毫秒
    var total_all_time = 0; // 单位是秒
    var total_idle_time = 0;
    var total_shutdown_time = 0;
    var total_off_time = 0;
    var total_total_time = 0; // ms
    for(var i=0; i<array.length; i++)
    {
      var on_time = 0; // 除关机以外的时间
      var run_time = 0;
      var run_start = 0;
      var run_end = 0;
      var idle_time = 0;
      var idle_start = 0;
      var idle_end = 0;
      var shutdown_time = 0;
      var shutdown_start = 0;
      var shutdown_end = 0;
      var last_time = 0;
      var last_mode = "";
      var last_id = 0;
      var currentTime = 0;
      var flag_starttime = 0;
      var flag_endtime = 0;
      var temp = new Array();
      if( flag )
      {
        flag_starttime = starttime;
        flag_endtime = flag_starttime + 3600*1000;
        if( suc.length > 0 )
        {
          while( flag_endtime < suc[0].Time )
          {
            var json = {};
            date.setTime(flag_starttime);
            json["date"] = date.toLocaleDateString();
            json["hour"] = date.getHours();
            json["rate"] = 0;
            temp.push(json);
            flag_starttime += 3600000;
            flag_endtime += 3600000;
          }
        }
      }
      else
      {
        last_time = array[i].last_time;
        last_mode = array[i].last_mode;
        last_id = array[i].last_id;
        if( last_mode == "Run" )
          run_start = last_time;
        else if( last_mode == "Idle" )
          idle_start = last_time;
        else if( last_mode == "Shutdown" )
          shutdown_start = last_time;
      }

      while(true)
      {
        var machine_starttime = array[i].last_time;
        if( suc.length == 0 )
          machine_starttime = 0;
        for(var k=0; k<suc.length; k++)
        {
          if( array[i].MachineName != suc[k].MachineName )
            continue;
          if( flag )
          {
            if( suc[k].Time < flag_starttime )
              continue;
            else if( suc[k].Time >= flag_endtime )
              break;
          }
          currentTime = parseInt(suc[k].Time);
          if( machine_starttime == 0 )
            machine_starttime = currentTime;
          // 判断是否有关机过程
          if( last_time > 0 && (currentTime - last_time) > g_nOffTime ) // 间隔时间大于10分钟
          {
            //console.log(array[i].name + '关机，从' + last_time + '到' + currentTime + ', 时长：' + (currentTime - last_time));
            if( last_mode == "Run" && run_start > 0 )
            {
              run_time += (last_time - run_start);
            }
            if( last_mode == "Idle" && idle_start > 0 )
            {
              idle_time += (last_time - idle_start);
            }
            if( last_mode == "Shutdown" && shutdown_start > 0 )
            {
              shutdown_time += (last_time - shutdown_start);
            }
            run_start = 0;
            idle_start = 0;
            shutdown_start = 0;
          }
          last_time = currentTime;
          last_mode = suc[k].Operation_Mode;
          last_id = parseInt(suc[k].id);

          // 计算运行时间
          run_end = currentTime;
          if( suc[k].Operation_Mode == "Run" )
          {
            if( run_start == 0 )
              run_start = run_end;
          }
          else if( run_start > 0 )
          {
            run_time += (run_end - run_start);
            run_start = 0;
            run_end = 0;
          }

          // 计算等待时间
          idle_end = currentTime;
          if( suc[k].Operation_Mode == "Idle" )
          {
            if( idle_start == 0 )
              idle_start = idle_end;
          }
          else if( idle_start > 0 )
          {
            idle_time += (idle_end - idle_start);
            idle_start = 0;
            idle_end = 0;
          }

          // 计算故障时间
          shutdown_end = currentTime;
          if( suc[k].Operation_Mode == "Shutdown" )
          {
            if( shutdown_start == 0 )
              shutdown_start = shutdown_end;
          }
          else if( shutdown_start > 0 )
          {
            shutdown_time += (shutdown_end - shutdown_start);
            shutdown_start = 0;
            shutdown_end = 0;
          }
        }
        if( run_start > 0 )
        {
          if( run_end > run_start )
            run_time += (run_end - run_start);
          //else
          //  console.log(array[i].MachineName + ' run_end=' + run_end + ', run_start=' + run_start);
        }
        if( idle_start > 0 )
        {
          if( idle_end > idle_start )
            idle_time += (idle_end - idle_start);
          //else
          //  console.log(array[i].MachineName + ' idle_end=' + idle_end + ', idle_start=' + idle_start);
        }
        if( shutdown_start > 0 )
        {
          if( shutdown_end > shutdown_start )
            shutdown_time += (shutdown_end - shutdown_start);
          //else
          //  console.log(array[i].MachineName + ' shutdown_end=' + shutdown_end + ', shutdown_start=' + shutdown_start);
        }

        if( flag )
        {
          var json = {};
          date.setTime(flag_starttime);
          json["date"] = date.toLocaleDateString();
          json["hour"] = date.getHours();
          run_time /= 1000; // 由毫秒转成秒
          total_run_time += run_time;
          if( (flag_starttime + 3600 * 1000) > suc[suc.length-1].Time )
          {
            var gap = (suc[suc.length-1].Time - flag_starttime)/1000;
            json["rate"] = parseInt(0.5 + run_time*100/gap);
            if( json["rate"] > 100 )
              json["rate"] = 100;
            total_all_time += gap;
          }
          else
          {
            run_time += 18; // 四舍五入
            if( run_time > 3600 )
              run_time = 3600;
            json["rate"] = parseInt(run_time/36);
            total_all_time += 3600;
          }
          temp.push(json);
          flag_starttime = flag_endtime;
          flag_endtime = flag_starttime + 3600 * 1000;
          if( flag_starttime > suc[suc.length-1].Time )
          {
            break;
          }
          run_time = 0;
          run_start = 0;
          run_end = 0;
          idle_time = 0;
          idle_start = 0;
          idle_end = 0;
          shutdown_time = 0;
          shutdown_start = 0;
          shutdown_end = 0;
          last_time = 0;
          last_mode = "";
        }
        else
        {
          // 计算关机时间
          var total_time = endtime - starttime;
          if( suc.length > 0 )
            total_time = last_time - machine_starttime;
          if( total_time < 0 )
            total_time = 10;
          //if( month_jiadonglv == true )
          //  console.log('****** ' + array[i].MachineName + ' 已存总时长' + array[i].total_time + '，新增时长' + total_time + '，已存运行时间' + array[i].run_time + '，新增运行时间' + run_time);
          total_time += array[i].total_time;
          run_time += array[i].run_time;
          idle_time += array[i].idle_time;
          shutdown_time += array[i].shutdown_time;
          on_time = run_time + idle_time + shutdown_time;
          var off_time = total_time - on_time;
          if( endtime > starttime && req.body.mode != "hour" && req.body.starttime != undefined )
          {
            date.setTime(Date.parse(req.body.starttime));
            if( month_jiadonglv == true ) // 获取当月稼动率时才用
            {
              var month = getMonthDayTime(date);
              sql = "select * from currentmonth where month = '"+ month +"' and MachineName = '"+ array[i].MachineName +"'";
              let suc3 = await db_util.query(sql);
              if( suc3.length > 0 )
              {
                sql = "update currentmonth set run_time = '"+ run_time +"', idle_time = '"+ idle_time +"', ";
                sql += "shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"', ";
                sql += "total_time = '"+ total_time +"', last_time = '"+ last_time +"', ";
                sql += "last_id = '"+ last_id +"', ";
                sql += "last_mode = '"+ last_mode +"' ";
                sql += "where month = '"+ month +"' and MachineName = '"+ array[i].MachineName +"'";
              }
              else
              {
                sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
                sql += "values ('"+ month +"', '"+ array[i].MachineName +"', '"+ run_time +"', ";
                sql += "'"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"', '"+ total_time +"', "
                sql += "'"+ last_time +"', '"+ last_id +"', '"+ last_mode +"')";
              }
              await db_util.query(sql);
            }
          }
          array[i]["run_time"] = parseInt(run_time/1000);
          array[i]["idle_time"] = parseInt(idle_time/1000);
          array[i]["shutdown_time"] = parseInt(shutdown_time/1000);
          array[i]["off_time"] = parseInt(off_time/1000);
          array[i]["total_time"] = parseInt(total_time/1000);

          var json = {};
          json["hour"] = "";
          json["rate"] = parseInt(run_time*100/(total_time + spantime) + 0.5);
          if( isNaN(json["rate"]) )
            json["rate"] = 0;
          if( json["rate"] < 0 )
          {
            update = true;
            json["rate"] = 0;
          }
          else if( json["rate"] > 100 )
          {
            update = true;
            json["rate"] = 100;
          }
          temp.push(json);
          total_run_time += run_time;
          total_all_time += total_time/1000;
          total_idle_time += idle_time;
          total_shutdown_time += shutdown_time;
          total_off_time += off_time;
          total_total_time += total_time;
          break;
        }
      }
      if( flag )
      {
        if( req.body.endtime != undefined  )
          endtime = Date.parse(req.body.endtime);
        else
          endtime = Date.now();
        while( flag_starttime < endtime )
        {
          var json = {};
          date.setTime(flag_starttime);
          json["date"] = date.toLocaleDateString();
          json["hour"] = date.getHours();
          json["rate"] = 0;
          temp.push(json);
          flag_starttime += 3600000;
        }
      }
      array[i]["jiadonglv"] = temp;
    }

    if( month_jiadonglv == true && suc.length > 1 ) // 获取当月稼动率时才用
    {
      date.setTime(Date.parse(req.body.starttime));
      var month = getMonthDayTime(date);
      sql = "select * from currentmonth where month = '"+ month +"' and MachineName = 'total'";
      let suc4 = await db_util.query(sql);
      if( suc4.length > 0 )
      {
        sql = "update currentmonth set run_time = '"+ total_run_time +"', idle_time = '"+ total_idle_time +"', ";
        sql += "shutdown_time = '"+ total_shutdown_time +"', off_time = '"+ total_off_time +"', ";
        sql += "total_time = '"+ total_total_time +"', last_time = '"+ suc[suc.length-1].Time +"', ";
        sql += "last_id = '"+ suc[suc.length-1].id +"', ";
        sql += "last_mode = '"+ suc[suc.length-1].Operation_Mode +"' ";
        sql += "where month = '"+ month +"' and MachineName = 'total'";
      }
      else
      {
        sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
        sql += "values ('"+ month +"', 'total', '"+ total_run_time +"', ";
        sql += "'"+ total_idle_time +"', '"+ total_shutdown_time +"', '"+ total_off_time +"', '"+ total_total_time +"', "
        sql += "'"+ suc[suc.length-1].Time +"', '"+ suc[suc.length-1].id +"', '"+ suc[suc.length-1].Operation_Mode +"')";
      }
      await db_util.query(sql);

      cost_time = Date.now() - cost_time;
      sql = "当月稼动率统计 ";
      spantime = 0;
      for(var i=0; i<array.length; i++)
      {
        spantime += array[i]["jiadonglv"][0].rate;
        console.log('****** ' + array[i].MachineName + ' 总时长：' + array[i].total_time + '，运行时间：' + array[i].run_time + '，稼动率：' + array[i]["jiadonglv"][0].rate);
      }
      spantime /= array.length;
      console.log(sql + '运行时间：' + total_run_time + '，总时长：' + parseInt(total_all_time) + '，平均稼动率：' + spantime);
      if( suc.length > 0 )
        console.log('QueryCncTime cost time: ' + cost_time + 'ms, 最后一笔记录时间：' + suc[suc.length-1].Time);
      else
        console.log('QueryCncTime cost time: ' + cost_time + 'ms');
    }
    else if( month_jiadonglv == true && suc.length < 2 )
    {
      cost_time = Date.now() - cost_time;
      console.log('当月稼动率统计 没有更新，cost time: ' + cost_time + 'ms');
    }
    suc = null;
    if( update )
    {
      console.log('稼动率数据异常');
      date.setTime(Date.now());
      var month = getMonthDayTime(date);
      sql = "delete from cncmonth where month = '"+ month +"'";
      await db_util.query(sql);
      sql = "delete from currentmonth where month = '"+ month +"'";
      await db_util.query(sql);
    }
    res.status(200);
    res.json({"result":"ok","order":array});
  }
  catch(err)
  {
    res.status(200);
    res.json({"result":"error","order":array,"description":err.message});
  }
})

async function setTime(date, hours, minutes, seconds, milliseconds)
{
  date.setHours(hours);
  if( minutes != undefined )
    date.setMinutes(minutes);
  else
    date.setMinutes(0);
  if( seconds != undefined )
    date.setSeconds(seconds);
  else
    date.setSeconds(0);
  if( milliseconds != undefined )
    date.setMilliseconds(milliseconds);
  else
    date.setMilliseconds(0);
}

async function CalcHolidayTime(starttime, endtime, noSunday, calcStarttime)
{
  var dt = new Date();
  var currentTime = starttime;
  var st = 0, et = 0, spantime = 0; // 单位：毫秒
  var includeSunday = true;
  if( noSunday != undefined )
    includeSunday = false;
  var sql = "select * from cnctime where starttime != 'null'";
  let suc3 = await db_util.query(sql);
  if( calcStarttime != undefined )
  {
    dt.setTime(starttime);
    dt.setDate(1);
    setTime(dt, 0);
    sql = "select id, Time from cncdata where Time >= '"+ dt.getTime() +"' ORDER BY Time ASC LIMIT 1";
    let succ4 = await db_util.query(sql);
    if( succ4.length > 0 )
    {
      starttime = parseInt(succ4[0].Time);
      currentTime = starttime;
    }
  }
  while( currentTime < endtime )
  {
    dt.setTime(currentTime);
    if( dt.getDay() == 0 ) // 周日
    {
      setTime(dt, 8);
      st = dt.getTime();
      et = st + 24 * 3600 * 1000;
      if( starttime >= et || endtime <= st )
      {
        // 与周日没有交集
      }
      else if( includeSunday )
      {
        var flag = true;
        // 看看此周日是否被设置成休假或加班
        for(var i=0; i<suc3.length; i++)
        {
          var st2 = parseInt(suc3[i].starttime);
          var et2 = parseInt(suc3[i].endtime);
          if( suc3[i].starttime.indexOf('-') > 0 )
            st2 = Date.parse(suc3[i].starttime);
          if( suc3[i].endtime.indexOf('-') > 0 )
            et2 = Date.parse(suc3[i].endtime);
          if( st >= et2 || et <= st2 )
          {
            // 此周日和设置时间没有交集
          }
          else
          {
            //flag = false;
            if( st < st2 )
            {
              if( et <= et2 )
              {
                spantime += (et - st2);
              }
              else
              {
                spantime += (et2 - st2);
              }
            }
            else
            {
              if( et <= et2 )
              {
                spantime += (et - st);
              }
              else
              {
                spantime += (et2 - st);
              }
            }
          }
        }
        if( flag )
        {
          if( starttime < st )
          {
            if( endtime <= et )
            {
              spantime -= (endtime - st);
            }
            else
            {
              spantime -= (et - st);
            }
          }
          else
          {
            if( endtime <= et )
            {
              spantime -= (endtime - starttime);
            }
            else
            {
              spantime -= (et - starttime);
            }
          }
        }
      }
      currentTime += 7 * 24 * 3600000;
    }
    else
    {
      currentTime += (7 - dt.getDay()) * 24 * 3600000;
    }
  }
  for(var i=0; i<suc3.length; i++)
  {
    st = parseInt(suc3[i].starttime);
    et = parseInt(suc3[i].endtime);
    if( suc3[i].starttime.indexOf('-') > 0 )
      st = Date.parse(suc3[i].starttime);
    if( suc3[i].endtime.indexOf('-') > 0 )
      et = Date.parse(suc3[i].endtime);
    if( starttime >= et || endtime <= st )
    {
      // 没有交集
    }
    else
    {
      var offset = 0;
      if( starttime < st )
      {
        if( endtime <= et )
        {
          offset = endtime - st;
        }
        else
        {
          offset = et - st;
        }
      }
      else
      {
        if( endtime <= et )
        {
          offset = endtime - starttime;
        }
        else
        {
          offset = et - starttime;
        }
      }
      if( suc3[i].status == "0" ) // 休假
      {
        spantime -= offset;
      }
      else
      {
        spantime += offset;
      }
    }
  }
  /*dt.setTime(starttime);
  sql = "计算假期：" + getMonthDayTime(dt, 1) + " ~ ";
  dt.setTime(endtime);
  sql += getMonthDayTime(dt, 1);
  sql += "，时长：" + parseInt(spantime/3600000);
  console.log(sql);*/
  return spantime;
}

async function StatisticOee(body_MachineName, body_starttime, body_endtime)
{
  var date = new Date();
  var ret_json = {};
  try
  {
    let array = await StatisticUtilization(body_MachineName, body_starttime, body_endtime);
    var starttime = 0;
    var endtime = 0;
    var run_time = 0;
    var total_time = 0;
    var last_id = 0;
    for(var i=0; i<array.length; i++)
    {
      if( i == 0 )
        starttime = array[i]["start_time"];
      else if( array[i]["start_time"] < starttime )
        starttime = array[i]["start_time"];
      if( array[i]["last_time"] > endtime )
        endtime = array[i]["last_time"];
      run_time += array[i]["run_time"];
      total_time += (array[i]["last_time"] - array[i]["start_time"]);
      last_id = array[i]["lastID"];
    }
    starttime = Date.parse(body_starttime); // 这样就和按周、月统计的结果相同，否则在周日中计算扣除时间就有差别，如开始时间是10点则只扣22个小时
        
    // 开始计算OEE
    ret_json["run_time"] = run_time;
    ret_json["total_time"] = total_time;
    ret_json["last_time"] = endtime;
    ret_json["last_id"] = last_id;
    run_time /= 36000; // (ms --> hour)*100
    total_time /= 3600000; //  毫秒转成小时
    var oee = parseInt(run_time/total_time + 0.5);
    if( isNaN(oee) )
      oee = 0;
    console.log('StatistocOee oee: ' + run_time + '/' + total_time + ' = ' + oee);
    if( oee > 100 )
      oee = 100;
    var oee15 = 0;
    var spantime = await CalcHolidayTime(starttime, endtime); // 单位：毫秒
    total_time += (spantime * array.length / 3600000);
    if( (total_time*3600) < 1 ) // 如果总时间小于1秒，保证分母不为0
      total_time = 1/3600;
    oee15 = parseInt(run_time/total_time + 0.5);
    if( isNaN(oee15) )
      oee15 = 0;
    console.log('StatistocOee oee1.5: ' + run_time + '/' + total_time + ' = ' + oee15);
    if( oee15 > 100 )
      oee15 = 100;
    ret_json["result"] = "ok";
    ret_json["oee1"] = oee;
    ret_json["oee15"] = oee15;
    ret_json["total_time_15"] = parseInt(total_time * 3600000);
    if( body_MachineName != undefined )
    {
      var arrInfo = new Array();
      for(var i=0; i<array.length; i++)
      {
        var json = {};
        json["run_time"] = array[i]["run_time"];
        json["total_time"] = array[i]["total_time"];
        json["last_time"] = array[i]["last_time"];
        json["last_id"] = array[i]["last_id"];
        total_time = json["total_time"] + spantime;
        json["total_time_15"] = total_time;
        if( total_time < 10000 )
          total_time = 10000;
        json["oee1"] = parseInt(json["run_time"]/json["total_time"] + 0.5);
        json["oee15"] = parseInt(json["run_time"]/total_time + 0.5);
        if( json["oee1"] > 100 )
          json["oee1"] = 100;
        if( json["oee15"] > 100 )
          json["oee15"] = 100;
        arrInfo.push(json);
      }
      ret_json["order"] = arrInfo;
    }
    suc = null;
    return ret_json;
  }
  catch(error)
  {
    console.log('StatisticOee exception: ' + error.message);
    ret_json["result"] = "error";
    ret_json["oee1"] = 0;
    ret_json["oee15"] = 0;
    ret_json["description"] = error.message;
    return ret_json;
  }
}

app.post('/QueryCncOee', async (req, res) => {
  let ret = await StatisticOee(req.body.MachineName, req.body.starttime, req.body.endtime);
  res.status(200);
  res.json(ret);
})

app.post('/QueryCncOeeHour', function(req, res){
  if( req.body.starttime == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set starttime parameter"});
    return;
  }
  else
  {
    if( req.body.starttime < '2020-06-01 08:00:000' )
    {
      //console.log('QueryCncOeeHour starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  var date = new Date();
  var cost_time = date.getTime();
  //console.log('QueryCncOee from ' + req.ip + ' on ' + date.toLocaleString()); 
  var total_run_time = 0;
  var array = new Array();
  var arrIndex = {};
  var MachineName = "";
  if( req.body.MachineName != undefined )
    MachineName = req.body.MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["name"] = g_cncInfo[i].name;
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }
 
  var flag = false;
  var sql = "select MachineName, Time, fmtTime, Operation_Mode from cncdata";
  if( req.body.starttime != undefined )
  {
    if( flag )
    {
      sql += " and fmtTime >= '"+ req.body.starttime +"'";
    }
    else
    {
      flag = true;
      sql += " where fmtTime >= '"+ req.body.starttime +"'";
    }
  }
  if( req.body.endtime != undefined )
  {
    if( flag )
    {
      sql += " and fmtTime < '"+ req.body.endtime +"'";
    }
    else
    {
      flag = true;
      sql += " where fmtTime < '"+ req.body.endtime +"'";
    }
  }
  if( MachineName.length > 0 )
  {
    if( flag )
    {
      sql += " and MachineName = '"+ MachineName +"'";
    }
    else
    {
      flag = true;
      sql += " where MachineName = '"+ MachineName +"'";
    }
  }
  sql += " ORDER BY Time ASC";
  //console.log('QueryCncOeeHour: ' + sql);
  db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      var starttime = Date.parse(req.body.starttime); // 起始时间要不要从实际数据时间算起？？？
      var spantime = 3600 * 1000;
      var endtime = starttime + spantime;
      if( suc.length > 0 )
      {
        while( endtime <= suc[0].Time )
        {
          starttime += spantime;
          endtime += spantime;
        }
        if( starttime < suc[0].Time )
        {
          starttime = parseInt(suc[0].Time);
          spantime = endtime - starttime;
        }
      }
      var temp = new Array();
      var index = -1;
      var currentTime = 0;
      for(var k=0; k<suc.length; k++)
      {
        index = arrIndex[suc[k].MachineName];
        if( isNaN(index) )
          continue;
        currentTime = parseInt(suc[k].Time);
        if( array[index]["start_time"] == 0 )
          array[index]["start_time"] = currentTime;
        if( currentTime < endtime )
        {
          // 判断是否有关机过程
          if( array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime ) // 间隔时间大于10分钟
          {
            //console.log(array[index].name + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
            if( array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0 )
            {
              array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
            }
            array[index]["run_start"] = 0;
          }
          array[index]["last_time"] = currentTime;
          array[index]["last_mode"] = suc[k].Operation_Mode;

          // 计算运行时间
          array[index]["run_end"] = currentTime;
          if( suc[k].Operation_Mode == "Run" )
          {
            if( array[index]["run_start"] == 0 )
              array[index]["run_start"] = currentTime;
          }
          else if( array[index]["run_start"] > 0 )
          {
            array[index]["run_time"] += (currentTime - array[index]["run_start"]);
            array[index]["run_start"] = 0;
            array[index]["run_end"] = 0;
          }
        }
        else
        {
          var run_time = 0;
          for(var i=0; i<array.length; i++)
          {
            if( array[i]["last_mode"] == "Run" && array[i]["run_start"] > 0 )
            {
              array[i]["run_time"] += (array[i]["last_time"] - array[i]["run_start"]);
            }
            run_time += array[i]["run_time"];
            array[i]["run_time"] = 0;
            array[i]["run_start"] = 0;
            array[i]["run_end"] = 0;
          }
          total_run_time += run_time;
          run_time /= array.length;
          if( run_time > spantime )
            run_time = spantime;
          run_time *= 100;
          run_time /= spantime;
          run_time += 0.5; // 四舍五入
          var json = {};
          date.setTime(parseInt(starttime));
          json["hour"] = date.getHours();
          json["oee"] = parseInt(run_time);
          json["oee15"] = parseInt(run_time);
          if( json["oee"] > 100 )
            json["oee"] = 100;
          if( json["oee15"] > 100 )
            json["oee15"] = 100;
          temp.push(json);

          k --;
          spantime = 3600 * 1000;
          starttime = endtime;
          endtime = starttime + spantime;
        }
      }
      if( suc.length > 0 && suc[suc.length-1].Time < endtime )
      {
        var run_time = 0;
        var total_time = 0;
        for(var i=0; i<array.length; i++)
        {
          if( array[i]["last_mode"] == "Run" && array[i]["run_start"] > 0 )
          {
            array[i]["run_time"] += (array[i]["last_time"] - array[i]["run_start"]);
          }
          run_time += array[i]["run_time"];
          total_time += (array[i]["last_time"] - array[i]["start_time"]);
        }
        total_run_time += run_time;
        run_time /= array.length;
        if( (suc[suc.length-1].Time - starttime) < spantime )
        {
          spantime = suc[suc.length-1].Time - starttime;
          if( spantime < 1000 )
            spantime = 1000; // 防止分母为0
        }
        if( run_time > spantime )
          run_time = spantime;
        run_time *= 100;
        run_time /= spantime;
        run_time += 0.5; // 四舍五入
        var json = {};
        date.setTime(parseInt(starttime));
        json["hour"] = date.getHours();
        json["oee"] = parseInt(run_time);
        json["oee15"] = parseInt(run_time);
        if( json["oee"] > 100 )
          json["oee"] = 100;
        if( json["oee15"] > 100 )
          json["oee15"] = 100;
        temp.push(json);
      }
      if( suc.length > 0 )
      {
        if( req.body.endtime == undefined )
        {
          spantime = 3600 * 1000;
          starttime = endtime;
          currentTime = starttime + (12 - temp.length) * spantime;
          endtime = Date.now();
          if( endtime > currentTime )
            endtime = currentTime;
          while( starttime < endtime )
          {
            var json = {};
            date.setTime(parseInt(starttime));
            json["hour"] = date.getHours();
            json["oee"] = 0;
            json["oee15"] = 0;
            temp.push(json);
            starttime += spantime;
          }
        }
      }
      else
      {
        spantime = 3600 * 1000;
        starttime = Date.parse(req.body.starttime);
        currentTime = starttime + (12 - temp.length) * spantime;
        endtime = Date.now();
        if( endtime > currentTime )
          endtime = currentTime;
        while( starttime < endtime )
        {
          var json = {};
          date.setTime(parseInt(starttime));
          json["hour"] = date.getHours();
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          starttime += spantime;
        }
        if( temp.length == 0 )
        {
          var json = {};
          date.setTime(starttime);
          json["hour"] = date.getHours();
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          console.log('QueryCncOeeHour: find nothing from ' + getMonthDayTime(date, 1, 1));
        }
      }
      /*if( suc.length > 0 )
      {
        cost_time = Date.now() - cost_time;
        console.log('QueryCncOeeHour 运行时间:' + total_run_time + '，总时长:' + total_time);
        console.log('QueryCncOeeHour cost time: ' + cost_time + 'ms, 开始记录时间：' + suc[0].Time + '，最后记录时间：' + suc[suc.length-1].Time);
      }*/
      suc = null;
      res.status(200);
      res.json({"result":"ok", "oee":temp});
    },
    (err) =>
    {
      res.status(200);
      res.json({"result":"error", "description":err.message});
    }
  );
})

function getMonthDayTime(date, day, time)
{
  var ret = date.getFullYear() + '-';
  if( date.getMonth() < 9 )
    ret += '0';
  ret += (date.getMonth() + 1);
  if( day != undefined )
  {
    ret += '-';
    if( date.getDate() < 10 )
      ret += '0';
    ret += date.getDate();
    if( time != undefined )
    {
      ret += ' ';
      if( date.getHours() < 10 )
        ret += '0';
      ret += date.getHours();
      ret += ':';
      if( date.getMinutes() < 10 )
        ret += '0';
      ret += date.getMinutes();
      ret += ':';
      if( date.getSeconds() < 10 )
        ret += '0';
      ret += date.getSeconds();
    }
  }
  return ret;
}

function getYearWeek(time, weekonly)
{
  var date = new Date(time);
  setTime(date, 0);
  var dt = new Date(date.getFullYear(), 0, 1);
  var d = Math.round((date.getTime() - dt.getTime())/86400000);
  var weeks = Math.ceil((d + dt.getDay() + 1)/7);
  if( weekonly != undefined )
    return weeks;
  var ret = dt.getFullYear() + '-';
  if( weeks < 10 )
    ret += '0';
  ret += weeks;
  return ret;
}

async function StatisticOeeWeek(body_MachineName, body_starttime, body_endtime)
{
  var date = new Date();
  var cost_time = date.getTime();
  var array = new Array();
  var arrIndex = {};
  var MachineName = "";
  if( body_MachineName != undefined )
    MachineName = body_MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }
 
  var temp = new Array(); // 返回结果数组
  var flag = false;
  var starttime = Date.parse(body_starttime);
  var current_week = getYearWeek(date.getTime());
  date.setTime(starttime);
  if( date.getHours() != 0 )
  {
    setTime(date, 0);
    starttime = date.getTime();
  }
  var sql = getYearWeek(starttime);
  if( sql < current_week )
  {
    try
    {
      var firsttime = 0;
      let suc4 = await db_util.query("select value from cncother where name = 'firsttime'");
      if( suc4.length > 0 )
      {
        firsttime = parseInt(suc4[0].value);
      }
      else
      {
        let suc3 = await db_util.query("select Time, fmtTime from cncdata ORDER BY Time ASC LIMIT 1");
        if( suc3.length > 0 )
        {
          firsttime = parseInt(suc3[0].Time);
          var sql2 = "insert into cncother (name, value) values('firsttime', '"+ suc3[0].Time +"')";
          await db_util.query(sql2);
        }
      }
      if( firsttime > 0 )
      {
        var week = getYearWeek(firsttime);
        var start_week = getYearWeek(starttime);
        while( start_week < week )
        {
          var json = {};
          json["year"] = date.getFullYear();
          json["week"] = getYearWeek(starttime, 1);
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          starttime += 7 * 24 * 3600000;
          date.setTime(starttime);
          start_week = getYearWeek(starttime);
        }
        dt = null;
      }
      let suc2 = await db_util.query("select * from cncweek where name = '"+ MachineName +"'");
      for(var i=0; i<suc2.length; i++)
      {
        if( suc2[i].week < sql )
          continue;
        else if( suc2[i].week >= current_week )
          break;
        if( suc2[i].week < current_week )
        {
          var json = {};
          json["year"] = date.getFullYear();
          json["week"] = getYearWeek(starttime, 1);
          json["oee"] = suc2[i].oee;
          json["oee15"] = suc2[i].oee15;
          temp.push(json);
          starttime += 7 * 24 * 3600000;
          date.setTime(starttime);
          sql = getYearWeek(starttime);
        }
      }
      let suc5 = await db_util.query("select Time, fmtTime from cncdata ORDER BY Time DESC LIMIT 1");
      if( suc5.length > 0 )
      {
        var last_time = parseInt(suc5[0].Time);
        var week = getYearWeek(last_time);
        if( current_week > week )
          current_week = week;
        if( current_week <= sql )
        {
          starttime = date.getTime() - date.getDay() * 24 * 3600000;
          if( starttime > last_time ) // 最后一周需要实时计算
          {
            date.setTime(last_time);
            setTime(date, 0);
            starttime = date.getTime() - date.getDay() * 24 * 3600000;
            last_time = getYearWeek(starttime, 1);
            for(var i=temp.length-1; i>=0; i--)
            {
              if( temp[i]["week"] == last_time )
              {
                temp.splice(i, 1);
                break;
              }
            }
          }
        }
      }
      suc2 = null;
    }
    catch(err)
    {
      console.log('query cncweek error: ' + err.message);
    }
  }
  date.setTime(cost_time);
  sql = getMonthDayTime(date, 1, 1);
  date.setTime(starttime);
  console.log('StatisticOeeWeek on ' + sql + ', ' + body_starttime + ' from ' + starttime + ' [' + getMonthDayTime(date, 1, 1) + ']');

  sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  if( flag )
  {
    sql += " and Time >= '"+ starttime +"'";
  }
  else
  {
    flag = true;
    sql += " where Time >= '"+ starttime +"'";
  }
  var endtime_set = 0;
  if( body_endtime != undefined )
  {
    endtime_set = Date.parse(body_endtime);
    if( flag )
    {
      sql += " and Time < '"+ endtime_set +"'";
    }
    else
    {
      flag = true;
      sql += " where Time < '"+ endtime_set +"'";
    }
  }
  if( MachineName.length > 0 )
  {
    if( flag )
    {
      sql += " and MachineName = '"+ MachineName +"'";
    }
    else
    {
      flag = true;
      sql += " where MachineName = '"+ MachineName +"'";
    }
  }
  sql += " ORDER BY Time ASC";
  console.log('StatisticOeeWeek: ' + sql);
  try
  {
    let suc = await db_util.query(sql);

    date.setTime(starttime);
    var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    var endtime = dt.getTime() + (7 - dt.getDay()) * 24 * 3600000;
    if( endtime_set > 0 && endtime > endtime_set )
      endtime = endtime_set;
    var spantime = endtime - starttime;

    var index = suc.length;
    var currentTime = 0;
    var first_time = 0; // 该周的第一个数据，和最后一个数据一起统计spantime
    var last_time = 0;
    var begin_time = 0;
    var week_begin = 0; // 如果一周的前几天请假，那么这几天的时间就无法计算进去了，所以加了这个变量来保存一个星期的开始
    if( suc.length > 0 )
      begin_time = parseInt(suc[0].Time);
    for(var k=0; k<suc.length; k++)
    {
      index = arrIndex[suc[k].MachineName];
      if( isNaN(index) )
        continue;
      currentTime = parseInt(suc[k].Time);
      if( currentTime < endtime )
      {
        if( first_time == 0 )
          first_time = currentTime;
        last_time = currentTime;
        if( array[index]["start_time"] == 0 )
          array[index]["start_time"] = currentTime;
        // 判断是否有关机过程
        if( array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime ) // 间隔时间大于10分钟
        {
          //console.log(suc[k].MachineName + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
          if( array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0 )
          {
            array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
          }
          array[index]["run_start"] = 0;
        }
        array[index]["last_time"] = currentTime;
        array[index]["last_mode"] = suc[k].Operation_Mode;
        array[index]["last_id"] = parseInt(suc[k].id);

        // 计算运行时间
        array[index]["run_end"] = currentTime;
        if( suc[k].Operation_Mode == "Run" )
        {
          if( array[index]["run_start"] == 0 )
            array[index]["run_start"] = currentTime;
        }
        else if( array[index]["run_start"] > 0 )
        {
          array[index]["run_time"] += (currentTime - array[index]["run_start"]);
          array[index]["run_start"] = 0;
          array[index]["run_end"] = 0;
        }
      }
      else // 到了下一周了
      {
        var run_time = 0;
        var total_time = 0;
        for(var i=0; i<array.length; i++)
        {
          if( array[i]["last_time"] > 0 && (endtime - array[i]["last_time"]) > g_nOffTime ) // 间隔时间大于10分钟
          {
            if( array[i]["last_mode"] == "Run" && array[i]["run_start"] > 0 )
            {
              array[i]["run_time"] += (array[i]["last_time"] - array[i]["run_start"]);
            }
            array[i]["run_start"] = 0;
          }
          if( array[i]["run_start"] > 0 )
          {
            array[i]["run_time"] += (endtime - array[i]["run_start"]);
          }
          run_time += array[i]["run_time"];
          if( week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime )
          {
            total_time += (array[i]["last_time"] - week_begin);
          }
          else
          {
            total_time += (array[i]["last_time"] - array[i]["start_time"]);
          }
        }

        var run_time2 = run_time;
        if( total_time < run_time )
          total_time = run_time;
        spantime = total_time;
        date.setTime(starttime);
        var json = {};
        json["year"] = date.getFullYear();
        json["week"] = getYearWeek(starttime, 1);
        json["oee"] = parseInt(run_time*100/total_time + 0.5);
        console.log(getMonthDayTime(date, 1, 1) + ' ~ weekend');
        console.log('OEE运行时间：' + run_time + '，总时长：' + total_time + ', OEE = ' + json["oee"]);
        run_time = run_time2;
        index = endtime;
        endtime = last_time;
        if( first_time == begin_time )
        {
          spantime = await CalcHolidayTime(first_time, last_time);
        }
        else if( week_begin > 0 )
        {
          spantime = await CalcHolidayTime(week_begin, last_time);
        }
        else
        {
          spantime = await CalcHolidayTime(first_time, last_time, 1);
          spantime -= 24 * 3600000; // 有可能周日没有数据，first_time不是从周日开始的，所以周日统一扣除24小时的时间
        }
        var spantime_1 = spantime;
        spantime *= array.length;
        spantime += total_time;
        if( spantime < run_time )
          spantime = run_time;
        json["oee15"] = parseInt(run_time*100/spantime + 0.5);
        if( json["oee"] > 100 )
          json["oee"] = 100;
        if( json["oee15"] > 100 )
          json["oee15"] = 100;
        console.log('OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + json["oee15"]);
        temp.push(json);
        if( run_time > 0 )
        {
          var week = getYearWeek(date.getTime());
          if( MachineName.length == 0 )
          {
            sql = "select * from cncweek where week = '"+ week +"' and length(name) = 0";
            let succ4 = await db_util.query(sql);
            if( succ4.length == 0 )
              sql = "insert into cncweek (week, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('"+ week +"', '"+ json["oee"] +"', '"+ json["oee15"] +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ suc[k-1].Time +"', '"+ suc[k-1].id +"')";
            else
              sql = "update cncweek set oee = '"+ json["oee"] +"', oee15 = '"+ json["oee15"] +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ suc[k-1].Time +"', last_id = '"+ suc[k-1].id +"' where week = '"+ week +"' and length(name) = 0";
            await db_util.query(sql);
            succ4 = null;
          }
          for(var i=0; i<array.length; i++)
          {
            var name = MachineName;
            if( name.length == 0 )
              name = g_cncInfo[i].MachineName;
            run_time = array[i]["run_time"];
            if( week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime )
              total_time = (array[i]["last_time"] - week_begin);
            else
              total_time = (array[i]["last_time"] - array[i]["start_time"]);
            spantime = spantime_1 + total_time;
            if( total_time < run_time )
              total_time = run_time;
            if( spantime < run_time )
              spantime = run_time;
            var oee = parseInt(run_time*100/total_time + 0.5);
            var oee15 = parseInt(run_time*100/spantime + 0.5);
            if( oee > 100 )
              oee = 100;
            if( oee15 > 100 )
              oee15 = 100;
            sql = "select * from cncweek where week = '"+ week +"' and name = '"+ name +"'";
            let succ4 = await db_util.query(sql);
            if( succ4.length == 0 )
              sql = "insert into cncweek (week, name, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('"+ week +"', '"+ name +"', '"+ oee +"', '"+ oee15 +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ array[i]["last_time"] +"', '"+ array[i]["last_id"] +"')";
            else
              sql = "update cncweek set oee = '"+ oee +"', oee15 = '"+ oee15 +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ array[i]["last_time"] +"', last_id = '"+ array[i]["last_id"] +"' where week = '"+ week +"' and name = '"+ name +"'";
            await db_util.query(sql);
            succ4 = null;
          }
        }
        for(var i=0; i<array.length; i++)
        {
          array[i]["run_time"] = 0;
          array[i]["run_start"] = 0;
          array[i]["run_end"] = 0;
          array[i]["start_time"] = 0; 
        }
        k --;
        endtime = index;
        starttime = endtime;
        endtime = starttime + 7 * 24 * 3600000;
        if( endtime_set > 0 && endtime > endtime_set )
          endtime = endtime_set;
        spantime = endtime - starttime;
        first_time = 0;
        last_time = 0;
        week_begin = starttime;
      }
    }
    if( suc.length > 0 && suc[suc.length-1].Time < endtime )
    {
      var run_time = 0;
      var week_total_time = 0;
      for(var i=0; i<array.length; i++)
      {
        if( array[i]["run_start"] > 0 )
          array[i]["run_time"] += (array[i]["run_end"] - array[i]["run_start"]);
        run_time += array[i]["run_time"];
        if( week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime )
        {
          week_total_time += (array[i]["last_time"] - week_begin);
        }
        else
        {
          week_total_time += (array[i]["last_time"] - array[i]["start_time"]);
        }
      }
      var run_time2 = run_time;
      starttime = first_time;
      spantime = week_total_time;
      if( spantime < run_time )
        spantime = run_time;
      date.setTime(starttime);
      var json = {};
      json["year"] = date.getFullYear();
      json["week"] = getYearWeek(starttime, 1);
      json["oee"] = parseInt(run_time*100/spantime + 0.5);
      console.log('OEE运行时间：' + run_time + '，总时长：' + spantime + ', OEE = ' + json["oee"]);
      var total_time = spantime;
      var total_time_15 = total_time;
      run_time = run_time2;
      dt.setTime(starttime);
      if( dt.getHours() >= 8 )
      {
        setTime(dt, 8);
      }
      run_time2 = dt.getTime();
      endtime = parseInt(suc[suc.length-1].Time);
      if( week_begin > 0 )
        spantime = await CalcHolidayTime(week_begin, endtime);
      else
        spantime = await CalcHolidayTime(run_time2, endtime);
      var spantime_1 = spantime;
      spantime *= array.length;
      spantime += total_time_15;
      if( spantime < run_time )
        spantime = run_time;
      if( spantime < 1 ) // 防止run_time = 0
        spantime = 1;
      json["oee15"] = parseInt(run_time*100/spantime+0.5);
      if( json["oee"] > 100 )
        json["oee"] = 100;
      if( json["oee15"] > 100 )
        json["oee15"] = 100;
      console.log('OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + json["oee15"]);
      temp.push(json);
      if( run_time > 0 )
      {
        var week = getYearWeek(starttime);
        if( MachineName.length == 0 )
        {
          sql = "select * from cncweek where week = '"+ week +"'";
          let succ4 = await db_util.query(sql);
          if( succ4.length == 0 )
            sql = "insert into cncweek (week, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('"+ week +"', '"+ json["oee"] +"', '"+ json["oee15"] +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ suc[suc.length-1].Time +"', '"+ suc[suc.length-1].id +"')";
          else
            sql = "update cncweek set oee = '"+ json["oee"] +"', oee15 = '"+ json["oee15"] +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ suc[suc.length-1].Time +"', last_id = '"+ suc[suc.length-1].id +"' where week = '"+ week +"'";
          await db_util.query(sql);
          succ4 = null;
        }
      }
      for(var i=0; i<array.length; i++)
      {
        var name = MachineName;
        if( name.length == 0 )
          name = g_cncInfo[i].MachineName;
        run_time = array[i]["run_time"];
        if( week_begin > 0 && (array[i]["start_time"] - week_begin) > g_nOffTime )
          total_time = (array[i]["last_time"] - week_begin);
        else
          total_time = (array[i]["last_time"] - array[i]["start_time"]);
        spantime = spantime_1 + total_time;
        if( total_time < 1000 )
          total_time = 1000;
        if( spantime < 1000 )
          spantime = run_time * 2;
        var oee = parseInt(run_time*100/total_time + 0.5);
        var oee15 = parseInt(run_time*100/spantime + 0.5);
        if( oee > 100 )
          oee = 100;
        if( oee15 > 100 )
          oee15 = 100;
        sql = "select * from cncweek where week = '"+ week +"' and name = '"+ name +"'";
        let succ4 = await db_util.query(sql);
        if( succ4.length == 0 )
          sql = "insert into cncweek (week, name, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('"+ week +"', '"+ name +"', '"+ oee +"', '"+ oee15 +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ array[i]["last_time"] +"', '"+ array[i]["last_id"] +"')";
        else
          sql = "update cncweek set oee = '"+ oee +"', oee15 = '"+ oee15 +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ array[i]["last_time"] +"', last_id = '"+ array[i]["last_id"] +"' where week = '"+ week +"' and name = '"+ name +"'";
        await db_util.query(sql);
        succ4 = null;
      }
    }
    if( suc.length == 0 && temp.length == 0 )
    {
      var json = {};
      date.setTime(starttime);
      var json = {};
      json["year"] = date.getFullYear();
      json["week"] = getYearWeek(starttime, 1);
      json["oee"] = 0;
      json["oee15"] = 0;
      temp.push(json);
    }
console.log(JSON.stringify(temp));
    cost_time = Date.now() - cost_time;
    if( suc.length > 0 )
      console.log('StatisticOeeWeek cost time: ' + cost_time + 'ms, 最后一笔记录时间：' + suc[suc.length-1].Time);
    else
      console.log('StatisticOeeWeek cost time: ' + cost_time + 'ms');
    suc = null;
    suc3 = null;
  }
  catch(error)
  {
    console.log('StatisticOeeWeek error: ' + error.message);
  }
  return temp;
}

async function CalcOeeAgain(body_MachineName, body_starttime, body_endtime)
{
  var date = new Date();
  var cost_time = date.getTime();
  var month = getMonthDayTime(date);
  var sql = "delete from cncmonth where month = '"+ month +"'";
  await db_util.query(sql);
  sql = "delete from currentmonth where month = '"+ month +"'";
  await db_util.query(sql);
  await StatisticOeeMonth(body_MachineName, body_starttime, body_endtime);
  cost_time = Date.now() - cost_time;
  console.log('CalcOeeAgain end. cost time ' + cost_time);
}

async function StatisticOeeMonth(body_MachineName, body_starttime, body_endtime)
{
  var date = new Date();
  var cost_time = date.getTime();
  var array = new Array();
  var arrIndex = {};
  var MachineName = "";
  if( body_MachineName != undefined )
    MachineName = body_MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["start_time"] = 0; // 第一次记录的时间
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["last_id"] = 0;
    json["run_time"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    json["run_time_old"] = 0;
    json["idle_time_old"] = 0;
    json["shutdown_time_old"] = 0;
    json["total_time_old"] = 0;
    json["total_time_15_old"] = 0;
    json["idle_time"] = 0;
    json["idle_start"] = 0;
    json["idle_end"] = 0;
    json["shutdown_time"] = 0;
    json["shutdown_start"] = 0;
    json["shutdown_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }
 
  var temp = new Array(); // 返回结果数组
  var flag = false;
  var run_time_old = 0;
  var idle_time_old = 0;
  var shutdown_time_old = 0;
  var total_time_old = 0;
  var starttime = Date.parse(body_starttime);
  var current_month = getMonthDayTime(date);
  var endtime_set = 0;
  if( body_endtime != undefined )
  {
    endtime_set = Date.parse(body_endtime);
    date.setTime(endtime_set);
    current_month = getMonthDayTime(date);
  }
  date.setTime(starttime);
  if( date.getHours() != 0 )
  {
    console.log('StatisticOeeMonth starttime is ' + getMonthDayTime(date, 1, 1));
    setTime(date, 0);
    starttime = date.getTime();
  }
  var sql = getMonthDayTime(date);
  if( sql < current_month )
  {
    try
    {
      var firsttime = 0;
      let suc4 = await db_util.query("select value from cncother where name = 'firsttime'");
      if( suc4.length > 0 )
      {
        firsttime = parseInt(suc4[0].value);
      }
      else
      {
        let suc3 = await db_util.query("select Time, fmtTime from cncdata ORDER BY Time ASC LIMIT 1");
        if( suc3.length > 0 )
        {
          firsttime = parseInt(suc3[0].Time);
          var sql2 = "insert into cncother (name, value) values('firsttime', '"+ suc3[0].Time +"')";
          await db_util.query(sql2);
        }
      }
      if( firsttime > 0 )
      {
        var dt = new Date(firsttime);
        var month = getMonthDayTime(dt);
        var start_month = getMonthDayTime(date);
        while( start_month < month )
        {
          var json = {};
          json["year"] = date.getFullYear();
          json["month"] = date.getMonth() + 1;
          json["oee"] = 0;
          json["oee15"] = 0;
          temp.push(json);
          date.setMonth(date.getMonth()+1);
          sql = getMonthDayTime(date);
          starttime = date.getTime();
          start_month = getMonthDayTime(date);
        }
        dt = null;
      }
      let suc2 = await db_util.query("select * from cncmonth where name = '"+ MachineName +"'");
      for(var i=0; i<suc2.length; i++)
      {
        if( suc2[i].month < sql )
          continue;
        else if( suc2[i].month > current_month )
          break;
        if( suc2[i].month < current_month )
        {
          var json = {};
          json["year"] = date.getFullYear();
          json["month"] = date.getMonth() + 1;
          json["oee"] = suc2[i].oee;
          json["oee15"] = suc2[i].oee15;
          temp.push(json);
          date.setMonth(date.getMonth()+1);
          sql = getMonthDayTime(date);
          starttime = date.getTime();
        }
        else
        {
          run_time_old = parseInt(suc2[i].run_time);
          idle_time_old = parseInt(suc2[i].idle_time);
          shutdown_time_old = parseInt(suc2[i].shutdown_time);
          total_time_old = parseInt(suc2[i].total_time);
          var last_time = parseInt(suc2[i].last_time);
          if( last_time > 0 )
            starttime = last_time;
        }
      }
      if( MachineName.length == 0 )
      {
        sql = "select * from cncmonth where month = '"+ current_month +"' and length(name) > 0";
        let suc4 = await db_util.query(sql);
        for(var i=0; i<suc4.length; i++)
        {
          var index = arrIndex[suc4[i].name];
          if( isNaN(index) )
            continue;
          array[index]["run_time_old"] = parseInt(suc4[i].run_time);
          array[index]["idle_time_old"] = parseInt(suc4[i].idle_time);
          array[index]["shutdown_time_old"] = parseInt(suc4[i].shutdown_time);
          array[index]["total_time_old"] = parseInt(suc4[i].total_time);
          array[index]["total_time_15_old"] = parseInt(suc4[i].total_time_15);
          array[index]["last_time"] = parseInt(suc4[i].last_time);
          array[index]["last_mode"] = suc4[i].last_mode;
          array[index]["last_id"] = parseInt(suc4[i].last_id);
          array[index]["start_time"] = array[index]["last_time"];
          if( array[index]["last_mode"] == "Run" )
            array[index]["run_start"] = array[index]["last_time"];
        }
      }
      suc2 = null;
    }
    catch(err)
    {
      console.log('query cncmonth error: ' + err.message);
    }
  }
  date.setTime(cost_time);
  sql = getMonthDayTime(date, 1, 1);
  date.setTime(starttime);
  //console.log('StatisticOeeMonth on ' + sql + ', ' + body_starttime + ' from ' + starttime + ' [' + getMonthDayTime(date, 1, 1) + ']');

  sql = "select id, MachineName, Time, Operation_Mode from cncdata";
  if( flag )
  {
    sql += " and Time >= '"+ starttime +"'";
  }
  else
  {
    flag = true;
    sql += " where Time >= '"+ starttime +"'";
  }
  if( endtime_set > 0 )
  {
    if( flag )
    {
      sql += " and Time < '"+ endtime_set +"'";
    }
    else
    {
      flag = true;
      sql += " where Time < '"+ endtime_set +"'";
    }
  }
  if( MachineName.length > 0 )
  {
    if( flag )
    {
      sql += " and MachineName = '"+ MachineName +"'";
    }
    else
    {
      flag = true;
      sql += " where MachineName = '"+ MachineName +"'";
    }
  }
  sql += " ORDER BY Time ASC";
  //console.log(sql);
  try
  {
    let suc = await db_util.query(sql);

    date.setTime(starttime);
    date.setMonth(date.getMonth()+1);
    var dt = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
    var endtime = dt.getTime();
    if( endtime_set > 0 && endtime > endtime_set )
      endtime = endtime_set;
    var spantime = endtime - starttime;

    var index = suc.length;
    var currentTime = 0;
    var first_time = 0; // 月份的第一个数据，和最后一个数据一起统计spantime
    var last_time = 0;
    for(var k=0; k<suc.length; k++)
    {
      index = arrIndex[suc[k].MachineName];
      if( isNaN(index) || index < 0 || index >= array.length )
        continue;
      currentTime = parseInt(suc[k].Time);
      if( currentTime < endtime )
      {
        if( first_time == 0 )
          first_time = currentTime;
        last_time = currentTime;
        array[index]["last_id"] = suc[k].id;
        if( array[index]["start_time"] == 0 )
          array[index]["start_time"] = currentTime;
        // 判断是否有关机过程
        if( array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime ) // 间隔时间大于10分钟
        {
          //console.log(suc[k].MachineName + '关机，从' + array[index]["last_time"] + '到' + currentTime + ', 时长：' + parseInt((currentTime - array[index]["last_time"])));
          if( array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0 )
          {
            array[index]["run_time"] += (array[index]["last_time"] - array[index]["run_start"]);
          }
          if( array[index]["last_mode"] == "Idle" && array[index]["idle_start"] > 0 )
          {
            array[index]["idle_time"] += (array[index]["last_time"] - array[index]["idle_start"]);
          }
          if( array[index]["last_mode"] == "Shutdown" && array[index]["shutdown_start"] > 0 )
          {
            array[index]["shutdown_time"] += (array[index]["last_time"] - array[index]["shutdown_start"]);
          }
          array[index]["run_start"] = 0;
          array[index]["idle_start"] = 0;
          array[index]["shutdown_start"] = 0;
        }
        array[index]["last_time"] = currentTime;
        array[index]["last_mode"] = suc[k].Operation_Mode;

        // 计算运行时间
        array[index]["run_end"] = currentTime;
        if( suc[k].Operation_Mode == "Run" )
        {
          if( array[index]["run_start"] == 0 )
            array[index]["run_start"] = currentTime;
        }
        else if( array[index]["run_start"] > 0 )
        {
          array[index]["run_time"] += (currentTime - array[index]["run_start"]);
          array[index]["run_start"] = 0;
          array[index]["run_end"] = 0;
        }

        // 计算等待时间
        array[index]["idle_end"] = currentTime;
        if( suc[k].Operation_Mode == "Idle" )
        {
          if( array[index]["idle_start"] == 0 )
            array[index]["idle_start"] = currentTime;
        }
        else if( array[index]["idle_start"] > 0 )
        {
          array[index]["idle_time"] += (currentTime - array[index]["idle_start"]);
          array[index]["idle_start"] = 0;
          array[index]["idle_end"] = 0;
        }

        // 计算故障时间
        array[index]["shutdown_end"] = currentTime;
        if( suc[k].Operation_Mode == "Shutdown" )
        {
          if( array[index]["shutdown_start"] == 0 )
            array[index]["shutdown_start"] = currentTime;
        }
        else if( array[index]["shutdown_start"] > 0 )
        {
          array[index]["shutdown_time"] += (currentTime - array[index]["shutdown_start"]);
          array[index]["shutdown_start"] = 0;
          array[index]["shutdown_end"] = 0;
        }
      }
      else // 到了下一个月份了
      {
        console.log('previous month end.');
        var run_time = 0;
        var idle_time = 0;
        var shutdown_time = 0;
        var off_time = 0;
        var total_time = 0;
        for(var i=0; i<array.length; i++)
        {
          if( array[i]["run_start"] > 0 && array[i]["run_end"] > array[i]["run_start"] )
          {
            array[i]["run_time"] += (array[i]["run_end"] - array[i]["run_start"]);
          }
          if( array[i]["idle_start"] > 0 && array[i]["idle_end"] > array[i]["idle_start"] )
          {
            array[i]["idle_time"] += (array[i]["idle_end"] - array[i]["idle_start"]);
          }
          if( array[i]["shutdown_start"] > 0 && array[i]["shutdown_end"] > array[i]["shutdown_start"] )
          {
            array[i]["shutdown_time"] += (array[i]["shutdown_end"] - array[i]["shutdown_start"]);
          }
          run_time += array[i]["run_time"];
          idle_time += array[i]["idle_time"];
          shutdown_time += array[i]["shutdown_time"];
          if( array[i]["start_time"] > 0 && array[i]["last_time"] > array[i]["start_time"] )
            total_time += (array[i]["last_time"] - array[i]["start_time"]);
        }
        off_time = total_time - run_time - idle_time - shutdown_time;
        if( off_time < 0 )
          off_time = 0;
        var run_time2 = run_time;
        if( run_time > total_time )
          total_time = run_time;
        spantime = total_time;
        dt.setTime(starttime);
        var json = {};
        json["year"] = dt.getFullYear();
        json["month"] = dt.getMonth() + 1;
        json["oee"] = parseInt(run_time*100/total_time + 0.5);
        //console.log(json["year"] + '-' + json["month"] + ' oee = ' + json["oee"]);
        //console.log('OEE运行时间：' + run_time + '，总时长：' + total_time + ', OEE = ' + json["oee"]);
        run_time = run_time2;
        run_time2 = first_time; //starttime;
        index = endtime;
        endtime = last_time;
        spantime = await CalcHolidayTime(first_time, last_time, null, 1);
        var spantime_1 = spantime;
        spantime *= array.length;
        spantime += total_time;
        if( spantime < 1000 )
        {
          spantime = run_time;
          if( spantime == 0 )
            spantime = 1;
        }
        if( run_time > spantime )
          spantime = run_time;
        json["oee15"] = parseInt(run_time*100/spantime + 0.5);
        //console.log('OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + json["oee15"]);
        temp.push(json);
        {
          month = getMonthDayTime(dt);
          if( MachineName.length == 0 )
          {
            sql = "select * from cncmonth where month = '"+ month +"' and length(name) = 0";
            let succ4 = await db_util.query(sql);
            if( succ4.length == 0 )
              sql = "insert into cncmonth values('"+ month +"', '', '"+ json["oee"] +"', '"+ json["oee15"] +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ suc[k-1].Time +"', '"+ suc[k-1].id +"', '', '"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"')";
            else
              sql = "update cncmonth set oee = '"+ json["oee"] +"', oee15 = '"+ json["oee15"] +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ suc[k-1].Time +"', last_id = '"+ suc[k-1].id +"', idle_time = '"+ idle_time +"', shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"' where month = '"+ month +"' and length(name) = 0";
            await db_util.query(sql);
            succ4 = null;
          }
          for(var i=0; i<array.length; i++)
          {
            var name = MachineName;
            if( name.length == 0 )
              name = g_cncInfo[i].MachineName;
            run_time = array[i]["run_time"];
            idle_time = array[i]["idle_time"];
            shutdown_time = array[i]["shutdown_time"];
            total_time = (array[i]["last_time"] - array[i]["start_time"]);
            off_time = total_time - run_time - idle_time - shutdown_time;
            if( off_time < 0 )
              off_time = 0;
            spantime = spantime_1 + total_time;
            if( total_time < 1000 )
              total_time = 1000;
            if( spantime < 1000 )
            {
              spantime = run_time;
              if( spantime == 0 )
                spantime = 1;
            }
            if( run_time > total_time )
              total_time = run_time;
            if( run_time > spantime )
              spantime = run_time;
            var oee = parseInt(run_time*100/total_time + 0.5);
            var oee15 = parseInt(run_time*100/spantime + 0.5);
            sql = "select * from cncmonth where month = '"+ month +"' and name = '"+ name +"'";
            let succ4 = await db_util.query(sql);
            if( succ4.length == 0 )
              sql = "insert into cncmonth values('"+ month +"', '"+ name +"', '"+ oee +"', '"+ oee15 +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ array[i]["last_time"] +"', '"+ array[i]["last_id"] +"', '"+ array[i]["last_mode"] +"', '"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"')";
            else
              sql = "update cncmonth set oee = '"+ oee +"', oee15 = '"+ oee15 +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ array[i]["last_time"] +"', last_id = '"+ array[i]["last_id"] +"', last_mode = '"+ array[i]["last_mode"] +"', idle_time = '"+ idle_time +"', shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"' where month = '"+ month +"' and name = '"+ name +"'";
            await db_util.query(sql);
            succ4 = null;
          }
        }
        for(var i=0; i<array.length; i++)
        {
          array[i]["start_time"] = 0;
          array[i]["run_time"] = 0;
          array[i]["run_start"] = 0;
          array[i]["run_end"] = 0;
          array[i]["idle_time"] = 0;
          array[i]["idle_start"] = 0;
          array[i]["idle_end"] = 0;
          array[i]["shutdown_time"] = 0;
          array[i]["shutdown_start"] = 0;
          array[i]["shutdown_end"] = 0;
        }

        k --;
        endtime = index;
        dt.setTime(endtime);
        dt.setMonth(dt.getMonth()+1);
        dt.setDate(1);
        starttime = endtime;
        endtime = dt.getTime();
        if( endtime_set > 0 && endtime > endtime_set )
          endtime = endtime_set;
        spantime = endtime - starttime;
        first_time = 0;
        last_time = 0;
      }
    }
    if( suc.length > 0 && suc[suc.length-1].Time < endtime )
    {
      var run_time = run_time_old;
      var idle_time = idle_time_old;
      var shutdown_time = shutdown_time_old;
      var off_time = 0;
      var month_total_time = total_time_old;
      for(var i=0; i<array.length; i++)
      {
        if( array[i]["run_start"] > 0 && array[i]["run_end"] > array[i]["run_start"] )
          array[i]["run_time"] += (array[i]["run_end"] - array[i]["run_start"]);
        if( array[i]["idle_start"] > 0 && array[i]["idle_end"] > array[i]["idle_start"] )
          array[i]["idle_time"] += (array[i]["idle_end"] - array[i]["idle_start"]);
        if( array[i]["shutdown_start"] > 0 && array[i]["shutdown_end"] > array[i]["shutdown_start"] )
          array[i]["shutdown_time"] += (array[i]["shutdown_end"] - array[i]["shutdown_start"]);
        run_time += array[i]["run_time"];
        idle_time += array[i]["idle_time"];
        shutdown_time += array[i]["shutdown_time"];
        if( array[i]["start_time"] > 0 && array[i]["last_time"] > array[i]["start_time"] )
          month_total_time += (array[i]["last_time"] - array[i]["start_time"]);
        //else if( MachineName.length == 0 )
        //  console.log('提示: ' + g_cncInfo[i].MachineName + ' 结束时间小于开始时间 ' + array[i]["last_time"] + ' <= ' + array[i]["start_time"]);
      }
      var run_time2 = run_time;
      starttime = first_time;
      spantime = month_total_time;
      if( spantime < 1000 )
        spantime = 1000;
      if( run_time > spantime )
        spantime = run_time;
      dt.setTime(starttime);
      month = getMonthDayTime(dt);
      var json = {};
      json["year"] = dt.getFullYear();
      json["month"] = dt.getMonth() + 1;
      json["oee"] = parseInt(run_time*100/spantime + 0.5);
      //console.log('OEE运行时间：' + run_time + '，总时长：' + spantime + ', OEE = ' + run_time*100/spantime);
      var total_time = spantime;
      off_time = total_time - run_time - idle_time - shutdown_time;
      if( off_time < 0 )
        off_time = 0;
      var total_time_15 = total_time;
      run_time = run_time2;
      /*dt.setTime(starttime);
      if( dt.getHours() >= 8 )
      {
        setTime(dt, 8);
      }*/
      currentTime = parseInt(suc[suc.length-1].Time);
      dt.setTime(currentTime); // 必须计算本月所有的休息时间
      dt.setDate(1);
      setTime(dt, 0);
      run_time2 = dt.getTime();
      endtime = currentTime;//parseInt(suc[suc.length-1].Time);
      starttime = run_time2;
      spantime = await CalcHolidayTime(run_time2, endtime, null, 1);
      var spantime_1 = spantime;
      spantime *= array.length;
      //console.log('oee15 spantime: ' + parseInt(spantime_1/3600000) + '小时/台');
      spantime += total_time_15;
      if( spantime < run_time )
        spantime = run_time;
      json["oee15"] = parseInt(run_time*100/spantime + 0.5);
      //console.log('OEE1.5运行时间：' + run_time + '，总时长：' + spantime + ', OEE1.5 = ' + run_time*100/spantime);
      temp.push(json);
      if( json["oee15"] > 100 )
      {
        console.log('oee1.5计算异常？' + json["oee15"]);
        setTimeout(function() { CalcOeeAgain(body_MachineName, body_starttime, body_endtime); }, 1000);
      }
      if( MachineName.length == 0 )
      {
        sql = "select * from cncmonth where month = '"+ month +"' and length(name) = 0";
        let succ4 = await db_util.query(sql);
        if( succ4.length == 0 )
          sql = "insert into cncmonth values('"+ month +"', '', '"+ json["oee"] +"', '"+ json["oee15"] +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ suc[suc.length-1].Time +"', '"+ suc[suc.length-1].id +"', '', '"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"')";
        else
          sql = "update cncmonth set oee = '"+ json["oee"] +"', oee15 = '"+ json["oee15"] +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ suc[suc.length-1].Time +"', last_id = '"+ suc[suc.length-1].id +"', idle_time = '"+ idle_time +"', shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"' where month = '"+ month +"' and length(name) = 0";
        await db_util.query(sql);
        succ4 = null;
        sql = "select * from currentmonth where month = '"+ month +"' and MachineName = 'total'";
        let suc5 = await db_util.query(sql);
        if( suc5.length > 0 )
        {
          sql = "update currentmonth set run_time = '"+ run_time +"', idle_time = '"+ idle_time +"', ";
          sql += "shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"', ";
          sql += "total_time = '"+ total_time +"', last_time = '"+ suc[suc.length-1].Time +"', ";
          sql += "last_id = '"+ suc[suc.length-1].id +"', ";
          sql += "last_mode = '"+ suc[suc.length-1].Operation_Mode +"' ";
          sql += "where month = '"+ month +"' and MachineName = 'total'";
        }
        else
        {
          sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
          sql += "values ('"+ month +"', 'total', '"+ run_time +"', ";
          sql += "'"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"', '"+ total_time +"', "
          sql += "'"+ suc[suc.length-1].Time +"', '"+ suc[suc.length-1].id +"', '"+ suc[suc.length-1].Operation_Mode +"')";
        }
        await db_util.query(sql);
        suc5 = null;
      }
      for(var i=0; i<array.length; i++)
      {
        if( array[i]["start_time"] == 0 || array[i]["last_time"] <= array[i]["start_time"] )
        {
          continue;
        }
        var name = MachineName;
        if( name.length == 0 )
          name = g_cncInfo[i].MachineName;
        run_time = array[i]["run_time"] + array[i]["run_time_old"];
        idle_time = array[i]["idle_time"] + array[i]["idle_time_old"];
        shutdown_time = array[i]["shutdown_time"] + array[i]["shutdown_time_old"];
        total_time = (array[i]["last_time"] - array[i]["start_time"]);
        spantime = spantime_1 + total_time;
        total_time += array[i]["total_time_old"];
        spantime += array[i]["total_time_old"];
        off_time = total_time - run_time - idle_time - shutdown_time;
        if( off_time < 0 )
          off_time = 0;
        if( total_time < run_time )
          total_time = run_time;
        if( spantime < run_time )
          spantime = run_time;
        var oee = parseInt(run_time*100/total_time + 0.5);
        var oee15 = parseInt(run_time*100/spantime + 0.5);
        sql = "select * from cncmonth where month = '"+ month +"' and name = '"+ name +"'";
        let succ4 = await db_util.query(sql);
        if( succ4.length == 0 )
          sql = "insert into cncmonth values('"+ month +"', '"+ name +"', '"+ oee +"', '"+ oee15 +"', '"+ run_time +"', '"+ total_time +"', '"+ spantime +"', '"+ array[i]["last_time"] +"', '"+ array[i]["last_id"] +"', '"+ array[i]["last_mode"] +"', '"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"')";
        else
          sql = "update cncmonth set oee = '"+ oee +"', oee15 = '"+ oee15 +"', run_time = '"+ run_time +"', total_time = '"+ total_time +"', total_time_15 = '"+ spantime +"', last_time = '"+ array[i]["last_time"] +"', last_id = '"+ array[i]["last_id"] +"', last_mode = '"+ array[i]["last_mode"] +"', idle_time = '"+ idle_time +"', shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"' where month = '"+ month +"' and name = '"+ name +"'";
        await db_util.query(sql);
        succ4 = null;
        sql = "select * from currentmonth where month = '"+ month +"' and MachineName = '"+ name +"'";
        let suc5 = await db_util.query(sql);
        if( suc5.length > 0 )
        {
          sql = "update currentmonth set run_time = '"+ run_time +"', idle_time = '"+ idle_time +"', ";
          sql += "shutdown_time = '"+ shutdown_time +"', off_time = '"+ off_time +"', ";
          sql += "total_time = '"+ total_time +"', last_time = '"+ array[i]["last_time"] +"', ";
          sql += "last_id = '"+ array[i]["last_id"] +"', ";
          sql += "last_mode = '"+ array[i]["last_mode"] +"' ";
          sql += "where month = '"+ month +"' and MachineName = '"+ name +"'";
        }
        else
        {
          sql = "insert into currentmonth (month, MachineName, run_time, idle_time, shutdown_time, off_time, total_time, last_time, last_id, last_mode) ";
          sql += "values ('"+ month +"', '"+ name +"', '"+ run_time +"', ";
          sql += "'"+ idle_time +"', '"+ shutdown_time +"', '"+ off_time +"', '"+ total_time +"', "
          sql += "'"+ array[i]["last_time"] +"', '"+ array[i]["last_id"] +"', '"+ array[i]["last_mode"] +"')";
        }
        await db_util.query(sql);
        suc5 = null;
      }
    }
    if( suc.length == 0 && temp.length == 0 )
    {
      var json = {};
      dt.setTime(starttime);
      var json = {};
      json["year"] = dt.getFullYear();
      json["month"] = dt.getMonth() + 1;
      json["oee"] = 0;
      json["oee15"] = 0;
      temp.push(json);
    }

    cost_time = Date.now() - cost_time;
    /*if( suc.length > 0 )
      console.log('StatisticOeeMonth cost time: ' + cost_time + 'ms, 最新记录时间：' + suc[suc.length-1].Time + '，最新ID：' + suc[suc.length-1].id);
    else
      console.log('StatisticOeeMonth cost time: ' + cost_time + 'ms');*/
    suc = null;
    suc3 = null;
  }
  catch(error)
  {
    console.log('StatisticOeeMonth error: ' + error.message);
  }
  return temp;
}

app.post('/QueryCncOeeMonth', async (req, res) => {
  if( req.body.starttime == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set starttime parameter"})
    return;
  }
  else
  {
    if( req.body.starttime < "2019-06-01 08:00:00" )
    {
      //console.log('QueryCncOeeMonth starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  if( g_cncOeeMonthBusy )
  {
    console.log('QueryCncOeeMonth: the service is busy now');
    res.status(200);
    res.json({"result":"error", "description":"the service is busy now"})
    return;
  }
  g_cncOeeMonthBusy = true;

  let temp = await StatisticOeeMonth(req.body.MachineName, req.body.starttime, req.body.endtime);
  
  g_cncOeeMonthBusy = false;
  res.status(200);
  res.json({"result":"ok", "oee":temp});
})

app.post('/QueryCncOeeWeek', async (req, res) => {
  if( req.body.starttime == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set starttime parameter"})
    return;
  }
  else
  {
    if( req.body.starttime < "2019-06-01 08:00:00" )
    {
      //console.log('QueryCncOeeMonth starttime error: ' + req.body.starttime + ' from ' + req.ip);
      res.status(404);
      res.end();
      return;
    }
  }
  if( g_cncOeeMonthBusy )
  {
    console.log('QueryCncOeeWeek: the service is busy now');
    res.status(200);
    res.json({"result":"error", "description":"the service is busy now"})
    return;
  }
  g_cncOeeMonthBusy = true;

  let temp = await StatisticOeeWeek(req.body.MachineName, req.body.starttime, req.body.endtime);
  
  g_cncOeeMonthBusy = false;
  res.status(200);
  res.json({"result":"ok", "oee":temp});
})

function CalcBanciTime(currentTime, run_start)
{
  var json = {};
  json["run_time"] = 0;
  json["run_time_ye"] = 0;
  if( run_start < 1590940800000 ) // 2020-06-01 00:00:00
  {
    console.log('run_start is null');
    return json;
  }
  var dt = new Date(currentTime);
  var dt2 = new Date(run_start);
  if( currentTime <= run_start ) // 二者的时间差应该不超过24小时
  {
    console.log('CalcBanciTime 当前时间：' + getMonthDayTime(dt, 1, 1) + ', 开始时间：' + getMonthDayTime(dt2, 1, 1));
    return json;
  }
  var hour = dt.getHours();
  var start_hour = dt2.getHours();
  if( start_hour < 8 )
  {
    if( hour < start_hour ) // 到第二天了
    {
      setTime(dt2, 8);
      json["run_time_ye"] = dt2.getTime() - run_start;
      json["run_time"] = 12 * 3600 * 1000;
      setTime(dt2, 20);
      json["run_time_ye"] += (currentTime - dt2.getTime());
    }
    else if( hour < 8 )
    {
      json["run_time_ye"] = currentTime - run_start;
      json["run_time"] = 0;
    }
    else if( hour < 20 )
    {
      setTime(dt, 8);
      json["run_time_ye"] = dt.getTime() - run_start;
      json["run_time"] = currentTime - dt.getTime();
    }
    else
    {
      json["run_time"] = 12 * 3600 * 1000;
      json["run_time_ye"] = currentTime - run_start - json["run_time"];
    }
  }
  else if( start_hour < 20 ) // 8 <= start_hour < 20
  {
    if( hour < 8 )
    {
      setTime(dt, 20);
      json["run_time"] = dt.getTime() - run_start;
      json["run_time_ye"] = currentTime - dt.getTime();
    }
    else if( hour < 20 )
    {
      if( hour < start_hour ) // 到第二天了
      {
        setTime(dt2, 20);
        json["run_time"] = dt2.getTime() - run_start;
        json["run_time_ye"] = currentTime - dt2.getTime();
      }
      else
      {
        json["run_time"] = currentTime - run_start;
        json["run_time_ye"] = 0;
      }
    }
    else
    {
      setTime(dt, 20);
      json["run_time"] = dt.getTime() - run_start;
      json["run_time_ye"] = currentTime - dt.getTime();
    }
  }
  else // start_hour >= 20
  {
    if( hour < 8 )
    {
      json["run_time"] = 0;
      json["run_time_ye"] = currentTime - run_start;
    }
    else if( hour < 20 )
    {
      setTime(dt, 8);
      json["run_time"] = currentTime - dt.getTime();
      json["run_time_ye"] = dt.getTime() - run_start;
    }
    else
    {
      if( hour < start_hour ) // 到第二天了
      {
        json["run_time"] = 12 * 3600 * 1000;
        json["run_time_ye"] = currentTime - run_start - json["run_time"];
      }
      else
      {
        json["run_time"] = 0;
        json["run_time_ye"] = currentTime - run_start;
      }
    }
  }
  return json;
}

// 以下只计算指定月份中白班/夜班的OEE和OEE1.5
app.post('/QueryCncOeeMonthEx', async (req, res) => {
  if( req.body.starttime == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set starttime parameter"})
    return;
  }
  var date = new Date();
  var array = new Array();
  var arrIndex = {};
  var MachineName = "";
  if( req.body.MachineName != undefined )
    MachineName = req.body.MachineName;
  for(var i=0; i<g_cncInfo.length; i++)
  {
    if( MachineName.length > 0 && MachineName != g_cncInfo[i].MachineName )
      continue;
    var json = {};
    json["last_time"] = 0; // 上一次记录的时间，用于判断是否关机
    json["last_mode"] = "";
    json["last_hour"] = 100;
    json["run_time"] = 0; // 白班时间
    json["run_time_ye"] = 0; // 夜班时间
    json["run_total"] = 0;
    json["run_start"] = 0;
    json["run_end"] = 0;
    array.push(json);
    arrIndex[g_cncInfo[i].MachineName] = array.length - 1;
  }
 
  var starttime = Date.parse(req.body.starttime);
  var dt = new Date(starttime);
  var sql = 'QueryCncOeeMonthEx: ' + getMonthDayTime(dt, 1, 1);
  var month = dt.getMonth();
  dt.setMonth(month+1);
  var dt2 = new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0);
  var endtime = dt2.getTime();
  sql += (' ~ ' + getMonthDayTime(dt2, 1, 1));
  console.log(sql);

  sql = "select MachineName, Time, Operation_Mode from cncdata where Time >= '"+ starttime +"'";
  if( MachineName.length > 0 )
    sql += " and MachineName = '"+ MachineName +"'";
  sql += " ORDER BY Time ASC";
  //console.log(sql);
  try
  {
    let suc3 = await db_util.query("select * from cnctime");
    let suc = await db_util.query(sql);
    var currentTime = 0;
    if( suc.length > 0 )
    {
      if( starttime < suc[0].Time )
        starttime = parseInt(suc[0].Time);
      while( endtime <= starttime )
      {
        month = dt2.getMonth();
        dt2.setMonth(month+1);
        endtime = dt2.getTime();
      }
      currentTime = parseInt(suc[suc.length-1].Time);
      if( currentTime < endtime )
        endtime = currentTime;
    }
    var spantime = 0;
    var spantime_ye = 0;
    var index = 0;
    currentTime = starttime;
    month = 12 * 3600 * 1000;
    dt.setTime(currentTime);
    dt2.setTime(currentTime);
    setTime(dt2, 8);
    var st = dt2.getTime();
    var et = st + month;
    if( endtime <= (et + month/3) )
    {
      if( currentTime <= st )
      {
        spantime_ye += (st - currentTime);
        if( endtime <= et )
        {
          spantime += (endtime - st);
        }
        else
        {
          spantime += month;
          spantime_ye += (endtime - et);
        }
      }
      else if( currentTime <= et )
      {
        if( endtime <= et )
        {
          spantime += (endtime - currentTime);
        }
        else
        {
          spantime += (et - currentTime);
          spantime_ye += (endtime - et);
        }
      }
      else
      {
        spantime_ye += (endtime - currentTime);
      }
    }
    else
    {
      if( currentTime <= st )
      {
        spantime_ye += (st - currentTime);
        spantime += month;
        spantime_ye += month/3;
      }
      else if( currentTime <= et )
      {
        spantime += (et - currentTime);
        spantime_ye += month/3;
      }
      else
      {
        spantime_ye += (et + month/3 - currentTime);
      }
      currentTime = et + month/3;
      while((currentTime + month*2) <= endtime )
      {
        spantime += month;
        spantime_ye += month;
        currentTime += month*2;
      }
      st = currentTime + month*2/3;
      et = st + month;
      if( endtime <= st )
      {
        spantime_ye += (endtime - currentTime);
      }
      else if( endtime <= et )
      {
        spantime_ye += month*2/3;
        spantime += (endtime - st);
      }
      else
      {
        spantime_ye += month*2/3;
        spantime += month;
        spantime_ye += (endtime - et);
      }
    }
    var temp = new Array();
    for(var k=0; k<suc.length; k++)
    {
      index = arrIndex[suc[k].MachineName];
      if( isNaN(index) )
        continue;
      currentTime = parseInt(suc[k].Time);
      dt.setTime(currentTime);
      var hour = dt.getHours();
      // 判断是否有关机过程
      if( array[index]["last_time"] > 0 && (currentTime - array[index]["last_time"]) > g_nOffTime ) // 间隔时间大于10分钟
      {
        if( array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0 )
        {
          var ret = CalcBanciTime(array[index]["last_time"], array[index]["run_start"]);
          array[index]["run_time"] += ret.run_time;
          array[index]["run_time_ye"] += ret.run_time_ye;
        }
        array[index]["run_start"] = 0;
      }
      else if( array[index]["last_hour"] < 24 && hour != array[index]["last_hour"] )
      {
        if( array[index]["last_mode"] == "Run" && array[index]["run_start"] > 0 )
        {
          if( (array[index]["last_hour"] == 7 && hour == 8) || (array[index]["last_hour"] == 19 && hour == 20) )
          {
            var ret = CalcBanciTime(currentTime, array[index]["run_start"]);
            array[index]["run_time"] += ret.run_time;
            array[index]["run_time_ye"] += ret.run_time_ye;
            array[index]["run_start"] = 0;
            //if( index == 0 )
            //  console.log(getMonthDayTime(dt, 1, 1) + ' - 2 白班/夜班时间: ' + ret.run_time + '/' + ret.run_time_ye);
          }
        }
      }
      array[index]["last_hour"] = hour;
      array[index]["last_time"] = currentTime;
      array[index]["last_mode"] = suc[k].Operation_Mode;

      // 计算运行时间
      array[index]["run_end"] = currentTime;
      if( suc[k].Operation_Mode == "Run" )
      {
        if( array[index]["run_start"] == 0 )
          array[index]["run_start"] = currentTime;
      }
      else if( array[index]["run_start"] > 0 )
      {
        var ret = CalcBanciTime(currentTime, array[index]["run_start"]);
        array[index]["run_time"] += ret.run_time;
        array[index]["run_time_ye"] += ret.run_time_ye;
        array[index]["run_start"] = 0;
        array[index]["run_end"] = 0;
      }
      if( k == suc.length-1 )
      {
        for(var i=0; i<array.length; i++)
        {
          if( array[i]["run_start"] > 0 )
          {
            var ret = CalcBanciTime(array[i]["run_end"], array[i]["run_start"]);
            array[index]["run_time"] += ret.run_time;
            array[index]["run_time_ye"] += ret.run_time_ye;
          }
        }
      }
    }
    if( suc.length > 0 )
    {
      var run_time = 0;
      var run_time_ye = 0;
      for(var i=0; i<array.length; i++)
      {
        run_time += array[i]["run_time"];
        run_time_ye += array[i]["run_time_ye"];
      }
      run_time = parseInt(run_time / array.length);
      run_time_ye = parseInt(run_time_ye / array.length);
      currentTime = parseInt(run_time*100/spantime + 0.5);
      if( currentTime > 100 )
        currentTime = 100;
      var json = {};
      json["oee"] = currentTime;
      json["oee_ye"] = parseInt(run_time_ye*100/spantime_ye + 0.5);
      json["oee_all"] = parseInt((run_time + run_time_ye)*100/(spantime + spantime_ye) + 0.5);
      console.log('OEE 白班：' + run_time + '/' + spantime + ' = ' + json["oee"] + '，夜班：' + run_time_ye + '/' + spantime_ye + ' = ' + json["oee_ye"] + '，平均：' + json["oee_all"]);
      if( json["oee_ye"] > 100 )
        json["oee_ye"] = 100;
      if( json["oee_all"] > 100 )
        json["oee_all"] = 100;
      currentTime = starttime;
      month = 12 * 3600 * 1000;
      while( currentTime < endtime )
      {
        dt.setTime(currentTime);
        if( dt.getDay() == 0 )
        {
          if( (currentTime + 2*month) <= endtime )
          {
            spantime -= month;
            spantime_ye -= month;
          }
          else
          {
            dt2.setTime(currentTime);
            setTime(dt2, 8);
            st = dt2.getTime();
            et = st + month;
            if( endtime <= st )
            {
              spantime_ye -= (endtime - currentTime);
            }
            else if( endtime <= et )
            {
              if( currentTime < st )
              {
                spantime_ye -= (st - currentTime);
                spantime -= (endtime - st);
              }
              else
              {
                spantime -= (endtime - currentTime);
              }
            }
            else
            {
              if( currentTime < st )
              {
                spantime_ye -= (st - currentTime);
                spantime -= month;
                spantime_ye -= (endtime - et);
              }
              else if( currentTime < et )
              {
                spantime -= (et - currentTime);
                spantime_ye -= (endtime - et);
              }
              else
              {
                spantime_ye -= (endtime - currentTime);
              }
            }
          }
          currentTime += 7 * 2 * month;
        }
        else
        {
          currentTime += 2 * month;
          dt2.setTime(currentTime);
          setTime(dt2, 8);
          currentTime = dt2.getTime();
        }
      }
      for(var i=0; i<suc3.length; i++)
      {
        st = parseInt(suc3[i].starttime);
        et = parseInt(suc3[i].endtime);
        if( suc3[i].starttime.indexOf('-') > 0 )
          st = Date.parse(suc3[i].starttime);
        if( suc3[i].endtime.indexOf('-') > 0 )
          et = Date.parse(suc3[i].endtime);
        if( st >= endtime || et <= starttime )
        {
        }
        else
        {
          var flag = 1;
          if( suc3[i].status == "0" ) // 休假
            flag = -1;
          index = parseInt(suc3[i].hours);
          if( et > endtime )
          {
            index -= parseInt((et - endtime)/3600000); // 这里可能存在着1个小时的误差
          }
          while( index >= 24 )
          {
            spantime += month * flag;
            spantime_ye += month * flag;
            index -= 24;
          }
          dt.setTime(st);
          hour = dt.getHours();
          if( hour < 8 )
          {
            if( (hour + index) < 8 )
            {
              spantime_ye += index * 3600000 * flag;
            }
            else if( (hour + index) < 20 )
            {
              spantime_ye += (8 - hour) * 3600000 * flag;
              spantime += (hour + index - 8) * 3600000 * flag;
            }
            else
            {
              spantime_ye += (8 - hour) * 3600000 * flag;
              spantime += month * flag;
              spantime_ye += (hour + index - 20) * 3600000 * flag;
            }
          }
          else if( hour < 20 )
          {
            if( (hour + index) < 20 )
            {
              spantime += index * 3600000 * flag;
            }
            else if( (hour + index) < 32 )
            {
              spantime += (20 - hour) * 3600000 * flag;
              spantime_ye += (hour + index - 20) * 3600000 * flag;
            }
            else
            {
              spantime += (20 - hour) * 3600000 * flag;
              spantime_ye += month * flag;
              spantime += (hour + index - 32) * 3600000 * flag;
            }
          }
          else
          {
            if( (hour + index) < 32 )
            {
              spantime_ye += (hour + index - 20) * 3600000 * flag;
            }
            else if( (hour + index) < 44 )
            {
              spantime_ye += (32 - hour) * 3600000 * flag;
              spantime += (hour + index - 32) * 3600000 * flag;
            }
            else
            {
              spantime_ye += (32 - hour) * 3600000 * flag;
              spantime += month * flag;
              spantime_ye += (hour + index - 44) * 3600000 * flag;
            }
          }
        }
      }
      if( spantime < 1000 )
      {
        console.log('spantime = ' + spantime);
        spantime = run_time;
        if( spantime < 1000 )
          spantime = 1000;
      }
      if( spantime_ye < 1000 )
      {
        console.log('spantime_ye = ' + spantime_ye);
        spantime_ye = run_time_ye;
        if( spantime_ye < 1000 )
          spantime_ye = 1000;
      }
      json["oee15"] = parseInt(run_time*100/spantime + 0.5);
      json["oee15_ye"] = parseInt(run_time_ye*100/spantime_ye + 0.5);
      json["oee15_all"] = parseInt((run_time + run_time_ye)*100/(spantime + spantime_ye) + 0.5);
      console.log('OEE1.5 白班：' + run_time + '/' + spantime + ' = ' + json["oee15"] + '，夜班：' + run_time_ye + '/' + spantime_ye + ' = ' + json["oee15_ye"] + '，平均：' + json["oee15_all"]);
      if( json["oee15"] > 100 )
        json["oee15"] = 100;
      if( json["oee15_ye"] > 100 )
        json["oee15_ye"] = 100;
      if( json["oee_all"] > 100 )
        json["oee_all"] = 100;
      temp.push(json);
    }
    res.status(200);
    res.json({"result":"ok", "oee":temp});
  }
  catch(error)
  {
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryCncStatisticStatus', async(req, res) =>{
  var date = new Date();
  console.log('QueryCncStatisticStatus from ' + req.ip + ' on ' + getMonthDayTime(date, 1, 1)); 
  var temp = new Array();
  let array = await StatisticUtilization(req.body.MachineName, req.body.starttime, req.body.endtime);
  for(var i=0; i<array.length; i++)
  {
    var json = {};
    json["name"] = array[i]["name"];
    json["MachineName"] = array[i]["MachineName"];
    json["idle_time"] = parseInt(array[i]["idle_time"]/36000 + 0.5)/100;
    json["idle_count"] = array[i]["idle_count"];
    json["shutdown_time"] = parseInt(array[i]["shutdown_time"]/36000 + 0.5)/100;
    json["shutdown_count"] = array[i]["shutdown_count"];
    json["off_time"] = parseInt(array[i]["off_time"]/36000 + 0.5)/100;
    json["off_count"] = array[i]["off_count"];
    temp.push(json);
  }
  res.status(200);
  res.json({"result":"ok", "status":temp});
})

let PdfToImage = function(file)
{
  return new Promise((resolve, reject) => {
    var pdf2img = require('pdf2img');
    pdf2img.setOptions({
      type: 'png',
      size: 1024,
      density: 600,
      outputdir: path.dirname(file) + path.sep + 'images',
      outputname: 'page',
      page: null
    });
    var t1 = process.uptime();
    pdf2img.convert(file, function(err, info) {
      if(err) 
      {
        console.log('pdf2img failed, ' + err.message);
        var json = {};
        json["result"] = "fail";
        json["message"] = err.message;
        reject(json);
      }
      else
      {
        var t2 = process.uptime();
        console.log('pdf2img cost time: ' + parseInt(t2 - t1));
        resolve(info);
      }
    });
  });
}

async function ValidDesignFiles(unionorder)
{
  try
  {
    var ext = "";
    var index = 0, xls = 0, pdf = 0, stp = 0;
    var sql = "select * from machining_files where union_order = '"+ unionorder +"' ORDER BY upload_time ASC";
    let suc2 = await db_util.query(sql);
    for(var i=0; i<suc2.length; i++)
    {
      console.log(suc2[i].file_name + '  ' + suc2[i].file_status);
      if( suc2[i].file_status != 1 )
        continue;
      sql = suc2[i].file_name.toLowerCase();
      index = sql.lastIndexOf('.');
      if( index < 1 )
        continue;
      ext = sql.substr(index+1);
      if( ext == 'xlsx' || ext == 'xls' )
      {
        xls ++;
      }
      else if( ext == 'pdf' )
      {
        pdf ++;
      }
      else if( ext == 'stp' )
      {
        stp ++;
      }
    }
    if( xls > 0 && pdf > 0 && stp > 0 )
    {
      var date = new Date();
      sql = "update machining_union_sheet set stage = '0100000000', sheji_endtime = '"+ getMonthDayTime(date, 1, 1) +"' where union_order = '"+ unionorder +"'";
      await db_util.query(sql);
      sql = "update machining_sheet set status = '1' where union_order = '"+ unionorder +"' and type_flag = 1";
      await db_util.query(sql);
    }
    else
    {
      sql = "update machining_union_sheet set stage = '1000000000', sheji_endtime = '' where union_order = '"+ unionorder +"'";
      await db_util.query(sql);
      sql = "update machining_sheet set status = '0' where union_order = '"+ unionorder +"' and type_flag = 1";
      await db_util.query(sql);

      sql = "";
      if( stp == 0 )
        sql = "STP文件 ";
      if( pdf == 0 )
        sql += "PDF文件 ";
      if( xls == 0 )
        sql += "BOM文件";
      sql += "没有上传或审核没有通过";
      console.log(sql);
    }
  }
  catch(error)
  {
    console.log('ValidDesignFiles error: ' + error.message);
  }
}

async function ParsePdfFile(unionorder, file, imageNo)
{
  var cost_time = Date.now();
  try
  {
    var sql = "select id, sheet_order from machining_sheet where union_order = '"+ unionorder +"' and type_flag = '1'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 ) // BOM表有没有导入
    {
      console.log('BOM表没有导入');
      return;
    }
    if( imageNo != undefined ) // 检查图档文件有没有审核通过
    {
      sql = "select * from machining_files where union_order = '"+ unionorder +"' ORDER BY upload_time ASC";
      let suc2 = await db_util.query(sql);
      var flag = 0;
      var name = imageNo.toLowerCase() + ".pdf";
      for(var i=0; i<suc2.length; i++)
      {
        var name1 = suc2[i].file_name.toLowerCase();
        if( name == name1 )
        {
          file = suc2[i].file_path;
          if( suc2[i].file_status == 1 )
            flag = 2;
          else
            flag = 1;
          break;
        }
      }
      if( flag == 0 ) // 还没有找到与图号同名的pdf文件
      {
        var count = 0; // pdf file count
        for(var i=0; i<suc2.length; i++)
        {
          name = suc2[i].file_name.toLowerCase();
          var index = name.lastIndexOf('.');
          if( index < 1 )
            continue;
          var ext = name.substr(index+1);
          if( ext != 'pdf' )
            continue;
          count ++;
          if( suc2[i].file_status == 1 )
          {
            flag ++;
            file = suc2[i].file_path;
          }
        }
        if( count > 0 )
        {
          // 有PDF文件，一旦有审核通过的，如果审核通过文件数量为1，就解析此文件；如果超过1，就解析最新的PDF文件（根据上传时间来判断）
          if( flag > 0 )
            flag = 2; // 可以解析了
          else
            flag = 1; // 文件还没有审核通过
        }
      }
      if( flag != 2 )
      {
        if( flag == 1 )
          console.log(unionorder + ' - ' + imageNo + '：图档PDF文件没有审核通过');
        else
          console.log(unionorder + ' - ' + imageNo + '：图档PDF文件没有找到（还没有上传吧？）');
        return;
      }
    }
    if(!fs.existsSync(file))
    {
      console.log("not find the file: " + file);
      return;
    }
    let info = await PdfToImage(file);
    if( info["result"] != "success" )
    {
      console.log('Failed to parse pdf file: ' + file);
      return;
    }
    var PDFToTextJS = require('pdftotextjs');
    var iconv = require('encoding');
    var i = 0, j = 0, k = 0, page = 0;
    var lastpage = info.message.length;
    var array = new Array(info.message.length);
    for(i=0; i<info.message.length; i++)
    {
      array[i] = null;
      page = i + 1;
      var pdf = new PDFToTextJS(file);
      pdf.add_options(['-f '+page, '-l '+page]);
      try
      {
        var data = pdf.getTextSync();
        if( data != undefined )
        {
          var newdata = iconv.convert(data, 'GBK'); // utf8 => GBK
          //var filepath = './public/' + unionorder + '/' + page + '.txt';
          //fs.writeFileSync(filepath, newdata);
          array[i] = newdata;
        }
      }
      catch(err)
      {
        console.log('PdfToText failed at page ' + page + ', ' + err.message);
      }
    }
    for(i=0; i<suc.length; i++)
    {
      var sheet_order = suc[i].sheet_order.toUpperCase();
      var buffer = Buffer.alloc(sheet_order.length*2);
      for(j=0; j<sheet_order.length; j++)
      {
        k = sheet_order.charCodeAt(j);
        buffer[j*2] = 0xA3;
        if( k > 0xFF00 )
          buffer[j*2+1] = k - 0xFF00 + 0xA0;
        else
          buffer[j*2+1] = 0x80 + k;
      }
      j = i + 5;
      if( j >= info.message.length )
        j = info.message.length - 1;
      for(; j>=0; j--)
      {
        if( array[j] == null )
          continue;
        page = j + 1;
        k = array[j].indexOf(buffer);
        if( j == 0 && k < 0 && info.message.length == suc.length )
        {
          console.log('hahaha page ' + (i+1));
          /*k = 1024;
          console.log(buffer);
          while( (k+32) <= array[j].length )
          {
            var temp = array[j].slice(k, k+32);
            console.log(temp);
            k += 32;
          }*/
          k = 1;
          j = i;
        }
        if( k > 0 )
        {
          var imagepath = "";
          if( (page - lastpage) > 1 )
          {
            for(k=lastpage+1; k<=page; k++)
            {
              sql = info.message[k-1].path.substr(9); // 去掉./public/
              imagepath += sql;
              if( k < page )
                imagepath += ',';
            }
          }
          else
          {
            imagepath = info.message[j].path.substr(9);
          }
          console.log(sheet_order + '对应的图片是 ' + imagepath);
          sql = "update machining_sheet set imagefile = '"+ imagepath +"' where id = '"+ suc[i].id +"'";
          await db_util.query(sql);
          j = -100;
          lastpage = page;
        }
      }
      if( j == -1 )
      {
        console.log('    Not find matched image');
      }
    }
    i = await ValidDesignFiles(unionorder);
    cost_time = Date.now() - cost_time;
    console.log('ParsePdfFile cost time: ' + parseInt(cost_time/1000) + ' sec');
  }
  catch(error)
  {
    console.log('ParsePdfFile error: ' + error.message);
  }
}

app.post('/DebugTest', async (req, res) =>{
  if(req.body.sql == undefined)
  {
    res.status(200);
    res.json({"result":"error", "description":"not find sql command line"});
    return;
  }
  console.log('DebugTest ' + req.ip + ": " + req.body.sql);
  if( req.body.sql == 'cncdata' )
  {
    var ret = "ok";
    do
    {
      if( req.body.evt_type == undefined )
      {
        ret = "evt_type not set";
        break;
      }
      if( req.body.starttime == undefined )
      {
        ret = "startime not set";
        break;
      }
      if( req.body.Operation_Mode == undefined )
      {
        ret = "Operation_Mode not set";
        break;
      }
      var i = 0, k = 0;
      var sql = "select * from cnctime where status = 0";
      let suc = await db_util.query(sql);
      var name = ['Fanuc-a-4ax', 'Mitsubishi-B-4ax', 'D1', 'D2', 'D3', 'D4'];
      var time = Date.parse(req.body.starttime);
      var date = new Date();
      var currTime = date.getTime();
      if( req.body.endtime != undefined )
      {
        currTime = Date.parse(req.body.endtime);
        if( isNaN(currTime) )
          currTime = date.getTime();
      }
      var array = new Array();
      sql = "insert into cncdata (evt_type, MachineName, Time, fmtTime, Operation_Mode) values ?";
      for(; time<=currTime; time+=300000) // 每隔5分钟（300秒）加一笔数据
      {
        for(i=0; i<suc.length; i++)
        {
          if( time >= suc[i].starttime && time <= suc[i].endtime )
            break;
        }
        if( i < suc.length )
          continue;
        date.setTime(time);
        if( date.getDay() == 0 )
        {
          if( date.getHours() >= 8 )
            continue;
        }
        else if( date.getDay() == 1 )
        {
          if( date.getHours() < 8 )
            continue;
        }
        for(i=0; i<6; i++)
        {
          date.setTime(time);
          var temp = new Array(5);
          temp[0] = req.body.evt_type;
          temp[1] = name[i];
          temp[2] = time;
          temp[3] = getMonthDayTime(date, 1, 1);
          temp[4] = req.body.Operation_Mode;
          array.push(temp);
          time += 1000;
        }
        time -= i * 1000;
        if( array.length >= 150 )
        {
          await db_util.query(sql, [array]);
          k += array.length;
          array.length = 0;
        }
      }
      if( array.length > 0 )
      {
        await db_util.query(sql, [array]);
        k += array.length;
      }
      ret = "Add " + k + " items";
    }while(false);
    res.status(200);
    res.json({"result":ret});
    return;
  }
  if( req.body.sql == 'modifystuff' )
  {
    try
    {
      var sql = "select * from machining_sheet where stuff != ''";
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        sql = "select * from base_material where material_no = '"+ suc[i].material_no +"'";
        let succ2 = await db_util.query(sql);
        if( succ2.length == 0 )
          continue;
        sql = "update machining_sheet set stuff2 = '"+ suc[i].stuff +"', stuff = '"+ succ2[0].name +"' where id = "+ suc[i].id +"";
        await db_util.query(sql);
        sql = "update dispatch_sheet set czhi = '"+ succ2[0].name +"' where union_order = '"+ suc[i].union_order +"' and ljmc = '"+ suc[i].sheet_order +"'";
        await db_util.query(sql);
      }
    }
    catch(error)
    {
      console.log('modifystuff error: ' + error.message);
    }
    res.status(200);
    res.json({"result":"ok"});
    return;
  }
  if(req.body.sql == 'moment')
  {
    var c = "";
    if( req.body.datetime == undefined)
      c = "datetime not set";
    else
      c = Date.parse(req.body.datetime);
    res.status(200);
    res.json({"utc":c});
    return;
  }
  if(req.body.sql == 'cncweek')
  {
    var ret = await StatisticOeeWeek(null, req.body.starttime, req.body.endtime);
    res.status(200);
    res.json({"result":ret});
    return;
  }
  if(req.body.sql == 'otdweek')
  {
    var date = new Date(Date.parse(req.body.starttime));
    var ret = getOTDWeek(date);
    res.status(200);
    res.json({"result":ret});
    return;
  }
  if(req.body.sql == 'queryuserInfo')
  {
    var json = {};
    json["result"] = "ok";
    json["userInfo"] = g_userInfo;
    res.status(200);
    res.json(json);
    return;
  }
  if(req.body.sql =='pdf2json')
  {
    var date = new Date();
    var file = './public/WAKS20200304ZCH002/k001.pdf';
    if( req.body.file != undefined )
      file = req.body.file;
    console.log(getMonthDayTime(date, 1, 1) + ' pdf2json: ' + file);
    var PDFToTextJS = require('pdftotextjs');
    var iconv = require('encoding');
    var cost_DL = "k-1-h-lkl---k1-k001-a01";
    var sheet_order = cost_DL.toUpperCase();
    var buffer = Buffer.alloc(sheet_order.length*2+3);
    buffer[0] = 0xA3;
    buffer[1] = 0xBA;
    buffer[2] = 0x20;
    for(var k=0; k<sheet_order.length; k++)
    {
      buffer[k*2+3] = 0xA3;
      buffer[k*2+4] = 0x80 + sheet_order.charCodeAt(k);
    }
    var pdf = new PDFToTextJS(file);
    pdf.add_options(['-f 4', '-l 4']);
    var data = pdf.getTextSync();
    var newdata = iconv.convert(data, 'GBK');
    if( newdata.indexOf(buffer) > 0 )
      console.log(sheet_order + ' is in page 4');
    fs.writeFileSync("./public/3.txt", newdata);
    res.status(200);
    res.json({"result":"ok"});
    return;
  }
  if( req.body.sql == 'parsepdf' )
  {
    if( req.body.unionorder == undefined )
    {
      res.status(200);
      res.json({"result":"not set unionorder"});
    }
    if( req.body.file == undefined )
    {
      res.status(200);
      res.json({"result":"not set file"});
    }
    try
    {
      await ParsePdfFile(req.body.unionorder, req.body.file, req.body.imageNo);
    }
    catch(err)
    {
      console.log('parsepdf error: ' + err.message);
    }
    res.status(200);
    res.json({"result":"ok"});
    return;
  }
  if( req.body.sql == 'alarmcall' )
  {
    var date = new Date();
    var starttime = getMonthDayTime(date, 1, 1);
    try
    {
      await execute_http_request(2, "测试", "L4", starttime, "alarm-D1-Test");
    }
    catch(error)
    {
      console.log('alarmcall error: ' + error.message);
    }
    res.status(200);
    res.json({"result":"ok"});
    return;
  }
  if( req.body.sql == 'alarmclear' )
  {
    if( req.body.name != undefined )
    {
      try
      {
        var sql = "select * from cncother where name = '"+ req.body.name +"'";
        let suc = await db_util.query(sql);
        if( suc.length > 0 )
        {
          var alarmTime = suc[0].reserved;
          var msg = req.body.name + " 警报解除";
          await execute_http_request_2(suc[0].value, msg);

          sql = "delete from cncother where name = '"+ req.body.name +"'";
          await db_util.query(sql);
          
          var date = new Date();
          msg = getMonthDayTime(date, 1, 1) + " 警报解除";
          sql = "update cncalarm set status = '"+ msg +"' where Time = '"+ alarmTime +"'";
          await db_util.query(sql);

          res.status(200);
          res.json({"result":"ok"});
        }
        else
        {
          res.status(200);
          res.json({"result":"error, not find the name"});
        }
      }
      catch(error)
      {
        res.status(200);
        res.json({"result":"error", "description":error.message});
      }
    }
    else
    {
      res.status(200);
      res.json({"result":"error, not set name value"});
    }
    return;
  }
  if( req.body.sql == 'import' )
  {
    try
    {
      var result = "";
      var obj = xlsx.parse('./public/basedata.xlsx');
      var i = 0;
      if( i == 0 )
      {
        var data = new Array();
        for(var k=1; k<obj[i].data.length; k++)
        {
          var temp = new Array(7);
          temp[0] = obj[i].data[k][0]; // 料号
          temp[1] = obj[i].data[k][1]; // 名称
          temp[2] = obj[i].data[k][2]; // 类别
          temp[4] = obj[i].data[k][3]; // 安全库存
          temp[3] = obj[i].data[k][4]; // 单位
          temp[5] = '0'; // 当前库存数量
          temp[6] = '';  // 架位
          data.push(temp);
        }
        var sql = "insert into base_material values ?";
        let sucData = await db_util.query(sql, [data]);
      }
      i = 1;
      if( i == 1 )
      {
        var data = new Array();
        for(var k=1; k<obj[i].data.length; k++)
        {
          var temp = new Array(3);
          temp[0] = obj[i].data[k][0]; // 全名
          temp[1] = '';
          temp[2] = obj[i].data[k][1];
          data.push(temp);
        }
        var sql = "insert into firm_info values ?";
        let sucData = await db_util.query(sql, [data]);
      }
      res.status(200);
      res.json({"result":"ok"});
    }
    catch(err)
    {
      console.log('Import base  failed, ' + err.message);
      res.status(200);
      var json = {};
      json["result"] = "error";
      json["description"] = err.message;
      res.json(json);
    }
    return;
  }
  if( req.body.sql == 'benefit' )
  {
    try
    {
      var date = new Date();
      var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
      var evt_dt = dt.getTime() - 24 * 3600 * 1000;
      var count = 0;
      if( req.body.count != undefined )
      {
        count = parseInt(req.body.count);
        if( isNaN(count) )
          count = 0;
      }
      var ret = "";
      if( req.body.type2 == undefined )
        ret = await execute_http_request_benefit_1(evt_dt, count, 22);
      else
        ret = await execute_http_request_benefit_2(evt_dt, count, 33.81);
      res.status(200);
      res.json({"reult":ret});
    }
    catch(err)
    {
      console.log('benefit failed, ' + err.message);
      res.status(200);
      res.json({"reult":"error","description":err.message});
    }
    return;
  }
  if( req.body.sql == "warehouse" )
  {
    if( req.body.file == undefined )
    {
      res.status(200);
      res.json({"result":"not set file"});
      return;
    }
    try
    {
      var array = await ParseWarehouseFile(req.body.file);
      res.status(200);
      res.json({"result":"ok", "order":array});
    }
    catch(error)
    {
      console.log('warehouse error: ' + error.message);
      res.status(200);
      res.json({"reult":"error","description":error.message});
    }
    return;
  }
  if( req.body.sql == 'calcholiday' )
  {
    if( req.body.starttime == undefined )
    {
       res.status(200);
      res.json({"result":"not set starttime"});
      return;
    }
    try
    {
      var starttime = Date.parse(req.body.starttime);
      var endtime = Date.now();
      if( req.body.endtime != undefined )
        endtime = Date.parse(req.body.endtime);
      var spantime = await CalcHolidayTime(starttime, endtime, null, 1);
      spantime /= 3600000;
      res.status(200);
      res.json({"result":"ok", "order":spantime});
    }
    catch(error)
    {
      console.log('calcholiday error: ' + error.message);
      res.status(200);
      res.json({"reult":"error","description":error.message});
    }
    return;
  }
  if( req.body.sql == 'kafka' )
  {
    setTimeout(function() { kafkaTest(); }, 200);
    res.status(200);
    res.json({"result":"wait a while and see the result in log"});
    return;
  }
  if( req.body.sql == 'workhour' )
  {
    try
    {
      var obj = xlsx.parse('./public/基礎數據維護及工時統計.xlsx');
      var data = new Array();
      var i, k, j = 0;
      for(i=0; i<obj[2].data.length; i++)
      {
        if( obj[2].data[i].length == 0 )
          continue;
        if( obj[2].data[i][0] != undefined )
        {
          j = i;
          continue;
        }
        for(k=2; k<obj[2].data[i].length; k++)
        {
          if( obj[2].data[i][k] == undefined )
          {
            k ++;
            continue;
          }
          var temp = new Array(4);
          temp[0] = obj[2].data[j][0];
          temp[1] = obj[2].data[j][k];
          if( i == (j+1) )
          {
            temp[2] = "";
            temp[3] = obj[2].data[i][k];
            k ++;

          }
          else
          {
            temp[2] = obj[2].data[i][k];
            k ++;
            temp[3] = obj[2].data[i][k];
          }
          data.push(temp);
        }
      }
      var sql = "insert into workhour values ?";
      let suc = await db_util.query(sql, [data]);
    }
    catch(error)
    {
      res.status(200);
      res.json({"result":error.message});
      return;
    }
    res.status(200);
    res.json({"result":"ok"});
    return;
  }

  try
  {
    let sucData = await db_util.query(req.body.sql);
    var json = {};
    var array = new Array();
    if( sucData.length > 0 )
    {
      sucData.forEach(element => {
        array.push(element);
      });
    }
    json["result"] = "ok";
    json["values"] = array;
    json["description"] = sucData.message;
    res.status(200);
    res.json(json);
  }
  catch(err)
  {
    res.status(200);
    res.json({"result":"error", "description":err.message});
  }
})

async function kafkaTest()
{
  console.log('kafka fetch message...');
  try
  {
    //wks.eform.t1.p79detail
    var errormsg = "";
    var kafkaTopic = "wks.eform.t1.p79detail";
    var kafkaURL = "hadopd01:9092,hadopd02:9092,hadopd03:9092";

    const KafkaManager = require('./Kafka/kafka-manager.js').KafkaManager;
    const OFFSET = require('./Kafka/kafka-manager.js').OFFSET;
    const km = new KafkaManager(kafkaURL, null, null, null);           // earliest/latest
    const consumer = km.setConsumer('kafkaGroupId201224', kafkaTopic, false, OFFSET.latest,
      (msg) => {
        var date = new Date();
        console.log('Fetch e-form data from Kafka on ' + getMonthDayTime(date, 1, 1));
        var objs = JSON.parse(msg.value);
        var sql = "select * from p79_tofsms where UniqueID = '"+ objs.UniqueID +"'";
        db_util.ExecuteSQL(sql, null,
          (sucData) =>
          {
            if( sucData.length == 0 )
            {
              sql = "insert into p79_tofsms values(null \
              , '"+ objs.UniqueID +"', '"+ objs.WorkOrder +"', '"+ objs.SequenceID +"', '"+ objs.ApplyID +"' \
              , '"+ objs.ApplyName +"', '"+ objs.ApplyDateTime +"', '"+ objs.ApplyerDeptID +"', '"+ objs.Location +"' \
              , '"+ objs.PIC +"', '"+ objs.ChargeDept +"', '"+ objs.Area +"', '"+ objs.RequestOwnerID +"' \
              , '"+ objs.RequestOwnerName +"', '"+ objs.RequestOwnerTel +"', '"+ objs.ExpectOFileName +"', '"+ objs.ExpecteFileName +"' \
              , '"+ objs.ToolName +"', '"+ objs.ToolTrNO +"', '"+ objs.ToolNum +"', '"+ objs.ToolWay +"', '"+ objs.ToolRemark +"' \
              , '"+ objs.Machine +"', '"+ objs.RequestDate +"', '"+ objs.CompleteDay +"', '')";
              db_util.ExecuteSQL(sql, null,
                (suc2) =>
                {
                  console.log('insert into p79_tofsms ' + suc2.affectedRows + ', ID: ' + suc2.insertId);

                  date.setTime(Date.parse(objs.RequestDate));
                  var RequestDate = getMonthDayTime(date, 1);
                  sql = "insert into machining_union_sheet (union_order, name, quatity, delivery_date, apply_person, applyDeptPIC,\
                    charge_department, delivery_addr, factory, machine_type, p79_id) values ('"+ objs.WorkOrder +"', '"+ objs.ToolName +"',\
                    '"+ objs.ToolNum +"', '"+ RequestDate +"', '"+ objs.ApplyName +"', '"+ objs.RequestOwnerName +"',\
                    '"+ objs.ChargeDept +"', '"+ objs.Area +"', '"+ objs.Location +"', '"+ objs.Machine +"', '"+ suc2.insertId +"')";
                  db_util.ExecuteSQL(sql, null,
                    (suc3) =>
                    {
                      console.log('insert into machining_union_sheet ' + suc3.affectedRows + ', ID: ' + suc3.insertId);
                    },
                    (err3) =>
                    {
                      console.log('Insert machining_union_sheet failed, ' + err3.message);
                      console.log(sql);
                    }
                  );
                },
                (err2) =>
                {
                  console.log('Insert p79_tofsms failed, ' + err2.message);
                  console.log(sql);
                }
              );
            }
          },
          (errData) =>
          {
            console.log('Query p79_tofsms failed, ' + errData.message);
          }
        );
      },
      (err) => {
        if( errormsg != err )
        {
          errormsg = err;
          var date = new Date();
          console.log('Kafka报错：' + getMonthDayTime(date, 1, 1));
          //console.log(err);
        }
      }
    );
  }
  catch(error)
  {
    console.log('Kafka exception: ' + error.message);
  }
}

async function ParseWarehouseFile(filePath)
{
  var cost_time = Date.now();
  var array = new Array();
  var i = filePath.lastIndexOf('.');
  try
  {
    if( i > 1 )
    {
      var sql = filePath.substr(i+1).toLowerCase();
      if( sql == 'xlsx' || sql == 'xls' )
      {
        var obj = xlsx.parse(filePath);
        for(i=0; i<obj.length; i++)
        {
          if( obj[i].data[0][0] == 'PR NO' )
          {
            var flag = false;
            var k = 0, j = 0;
            var date = new Date();
            var timestamp = getMonthDayTime(date, 1, 1);
            var data = new Array();
            var quatity = 0.0, qty_temp = 0.0;
            for(j=1; j<obj[i].data.length; j++)
            {
              flag = false;
              sql = "select * from base_material where material_no = '"+ obj[i].data[j][3] +"'";
              let suc1 = await db_util.query(sql);
              if( suc1.length > 0 )
              {
                sql = "select * from firm_info where fullname = '"+ obj[i].data[j][6] +"'";
                let suc2 = await db_util.query(sql);
                if( suc2.length > 0 )
                  flag = true;
              }
              if( flag )
              {
                var temp = new Array(13);
                temp[0] = null;
                for(k=0; k<10; k++)
                  temp[k+1] = obj[i].data[j][k];
                temp[k+1] = timestamp;
                temp[k+2] = '0';
                data.push(temp);
                quatity = parseFloat(suc1[0].stock);
                if( isNaN(quatity) )
                  quatity = 0;
                qty_temp = parseFloat(obj[i].data[j][4]);
                if( isNaN(qty_temp) )
                  qty_temp = 0;
                qty_temp += quatity;
                sql = qty_temp.toString();
                if( sql.indexOf('.') > 0 && sql.split('.')[1].length > 3 )
                  quatity = qty_temp.toFixed(3);
                else
                  quatity = qty_temp;
                sql = "update base_material set stock = '"+ quatity +"' where material_no = '"+ obj[i].data[j][3] +"'";
                await db_util.query(sql);
              }
              else
              {
                var json = {};
                json["PR_NO"] = obj[i].data[j][0];
                json["PO_NO"] = obj[i].data[j][1];
                json["SN"] = obj[i].data[j][2];
                json["material_no"] = obj[i].data[j][3];
                json["quatity"] = obj[i].data[j][4];
                json["price"] = obj[i].data[j][5];
                json["manufacturer"] = obj[i].data[j][6];
                json["currency"] = obj[i].data[j][7];
                json["check_no"] = obj[i].data[j][8];
                json["reason"] = obj[i].data[j][9];
                array.push(json);
              }
            }
            if( data.length > 0 )
            {
              sql = "insert into warehouse values ?"
              let suc = await db_util.query(sql, [data]);
              cost_time = Date.now() - cost_time;
              console.log('ParseWarehouseFile cost time ' + cost_time + ', ' + suc.message);
            }
            break;
          }
        }
      }
    }
  }
  catch(error)
  {
    console.log('ParseWarehouseFile error: ' + error.message);
  }
  return array;
}

async function CheckBOMFile(bomFile, unionorder)
{
  try
  {
    if(!fs.existsSync(bomFile))
    {
      return "";
    }
    var i = bomFile.lastIndexOf('.');
    if( i < 1 )
    {
      return "";
    }
    else
    {
      var ext = bomFile.substr(i+1).toLowerCase();
      if( ext != 'xlsx' && ext != 'xls' )
      {
        return "";
      }
    }
    console.log('CheckBOMFile: ' + bomFile);
    var ret = "";

    var obj = xlsx.parse(bomFile);
    for(i=0; i<obj.length; i++)
    {
      if( obj[i].name.indexOf("BOM") >= 0 )
      {
        break;
      }
    }
    if( i < obj.length )
    {
      var j = 6;
      var sql = "";
      var order = "";
      var addAll = true;
      if( obj[i].data[1].length > 15 ) // 模板中增加了“是否新增”这个栏位H：obj[i].data[j][7]
        order = obj[i].data[1][15];
      else
        order = obj[i].data[1][14];
      if( order != unionorder )
      {
        ret = "BOM表中工聯單號錯誤。";
        console.log('CheckBOMFile result: ' + ret);
        return ret;
      }
      if( obj[i].data[1].length > 15 )
      {
        for(var k=5; k<obj[i].data.length; k++)
        {
          if( obj[i].data[k][7] == "是" )
          {
            addAll = false;
            break;
          }
        }
      }
      for(var k=5; k<obj[i].data.length; k++)
      {
        // obj[i].data[k][]列表中：0/序号；1/类型（加工件还是标准件）；2/加工件图号或标准件名称；3/长；4/宽；5/高；6/料号；7/是否新增；
        // 8/材质；9/密度；10/用量（单台）；11/需求总量；12/总重量；13/发料员；14/领料员；15/备注
        if( obj[i].data[k][j] == null )
          continue;
        if( obj[i].data[k][j].length == 0 )
          continue;
        if( addAll == false )
        {
          if( obj[i].data[k][7] != "是" )
            continue;
        }
        sql = "select * from base_material where material_no = '"+ obj[i].data[k][j] +"'";
        let suc = await db_util.query(sql);
        if( suc.length == 0 )
        {
          if( ret.length > 0 )
            ret += "、";
          ret += obj[i].data[k][j];
        }
      }
    }
    if( ret.length > 0 )
    {
      sql = ret;
      ret = "料號" + sql + "不存在。";
      console.log('CheckBOMFile result: ' + ret);
    }
    else
    {
      console.log('CheckBOMFile result: OK');
    }
    return ret;
  }
  catch(error)
  {
    console.log('CheckBOMFile error: ' + error.message);
    return "";
  }
}

async function ParseBOMFile(bomFile)
{
  var sql = "";
  var order = "";
  try
  {
    if(!fs.existsSync(bomFile))
    {
      console.log('ParseBOMFile error, the file does not exist: ' + bomFile);
      return "the file does not exist";
    }
    var i = bomFile.lastIndexOf('.');
    if( i < 1 )
    {
      console.log('ParseBOMFile error, the file is not excel file: ' + bomFile);
      return "the file is not excel file";
    }
    else
    {
      var ext = bomFile.substr(i+1).toLowerCase();
      if( ext != 'xlsx' && ext != 'xls' )
      {
        console.log('ParseBOMFile error, the file is not excel file: ' + bomFile);
        return "the file is not excel file";
      }
    }
    console.log('ParseBOMFile: ' + bomFile);
    var ret = "ok";

    var obj = xlsx.parse(bomFile);
    for(i=0; i<obj.length; i++)
    {
      if( obj[i].name.indexOf("BOM") >= 0 )
      {
        break;
      }
    }
    if( i < obj.length )
    {
      if( obj[i].data[1].length > 15 ) // 模板中增加了“是否新增”这个栏位H：obj[i].data[j][7]
        order = obj[i].data[1][15];
      else
        order = obj[i].data[1][14];
      var quatity = obj[i].data[1][6];
      /*var name = obj[i].data[1][2];
      var delivery_date = getdate(obj[i].data[1][8]);
      var engineer = obj[i].data[1][12]; // 负责工程师
      var apply_person = obj[i].data[2][2];
      var apply_date = getdate(obj[i].data[2][6]);
      var telephone = obj[i].data[2][8];
      var charge_department = obj[i].data[2][12];
      var delivery_addr = obj[i].data[2][14];*/
      var name = "";
      var factory = "";
      var imageNo = obj[0].data[3][2];
      console.log('图号：' + imageNo);
      var jiagongjianshu = 0;
      var gongjianzongshu = 0;
      var addAll = true;
      var j = 0, k = 0;
      sql = "select name, factory from machining_union_sheet where union_order = '"+ order +"'";
      let sucData = await db_util.query(sql);
      if( sucData.length == 0 )
      {
        console.log('ParseBOMFile failed, the order does not exist');
        return "the order does not exist";
      }
      else
      {
        name = sucData[0].name;
        factory = sucData[0].factory;
      }
      if( obj[i].data[1].length > 15 )
      {
        j = 0;
        for(k=5; k<obj[i].data.length; k++)
        {
          if( obj[i].data[k][1] == null )
            continue;
          if( obj[i].data[k][1].length == 0 )
            continue;
          gongjianzongshu ++;
          if( obj[i].data[k][7] == "是" )
            j ++;
        }
        if( j > 0 && j < gongjianzongshu )
          addAll = false;
      }
      gongjianzongshu = 0;
      for(k=5; k<obj[i].data.length; k++)
      {
        if( obj[i].data[k][1] == null )
          continue;
        if( obj[i].data[k][1].length == 0 )
          continue;
        if( addAll == false )
        {
          if( obj[i].data[k][7] != "是" )
            continue;
        }
        gongjianzongshu ++;
        if( obj[i].data[k][1] == "加工件" )
          jiagongjianshu += 1;
      }
      var cnc = new Array(jiagongjianshu);
      jiagongjianshu = 0;
      var data = new Array(gongjianzongshu);
      gongjianzongshu = 0;
      for(k=5; k<obj[i].data.length; k++)
      {
        if( obj[i].data[k][1] == null )
          continue;
        if( obj[i].data[k][1].length == 0 )
          continue;
        if( addAll == false )
        {
          if( obj[i].data[k][7] != "是" )
            continue;
        }
        var temp = new Array(19);
        temp[0] = order; // 工联单号
        for(j=1; j<obj[i].data[1].length; j++)
        {
          if( obj[i].data[k][j] == null )
            sql = "";
          else
            sql = obj[i].data[k][j];
          if( obj[i].data[1].length > 15 )
          {
            if( j < 7 )
              temp[j] = sql;
            else if( j > 7 )
              temp[j-1] = sql;
          }
          else
          {
            temp[j] = sql;
          }
        }
        // temp[1]: 类型，标准件还是加工件; temp[2]: 标准件名称或加工件图号
        // temp[3/4/5]: length/width/height; temp[6]: material_no; temp[7]: stuff;
        // temp[8]: density; temp[9]: quatity; temp[10]: quatity_total; temp[11]: weight
        // temp[12]: material_issuer; temp[13]: picking_man; temp[14]: bom_remark
        // temp[15]: cnc_name, temp[16]: stuff2; temp[17]: type_flag; temp[18]: status
        var count = parseInt(temp[9]) * parseInt(quatity);
        if( parseInt(temp[10]) != count )
          temp[10] = count.toString();
        if( temp[1] == "加工件" )
        {
          if( temp[14] != "重點尺寸" && temp[14] != "重点尺寸" )
            temp[14] = "";
          var result = getcnc(temp[7], temp[3], temp[4], temp[10]);
          temp[15] = result["name"];
          temp[16] = result["id"];
          temp[17] = "1";
          temp[18] = "0"; // 0/设计；1/编程；2/加工；3/品检；4/二次加工；5/组装；6/总检；7/入库，解析了PDF文件之后再改为1
          sql = "select * from base_material where material_no = '"+ obj[i].data[k][6] +"'";
          let suc = await db_util.query(sql);
          if( suc.length > 0 && suc[0].name != '' )
          {
            temp[16] = temp[7];
            temp[7] = suc[0].name;
          }
          
          var cncTemp = new Array(9);
          cncTemp[0] = order; // 工联单号
          cncTemp[1] = name; // 治具名称
          cncTemp[2] = factory; // 厂别
          cncTemp[3] = temp[2]; // 零件名称
          if( temp[3] == "" )
          {
            cncTemp[4] = ""; // 图纸尺寸
          }
          else
          {
            if( temp[3][0] == 'D' || temp[3][0] == 'd' )
              cncTemp[4] = temp[3] + '*' + temp[5];
            else
              cncTemp[4] = temp[3] + '*' + temp[4] + '*' + temp[5];
          }
          cncTemp[5] = temp[7]; // 材质
          cncTemp[6] = temp[11]; // 总重量
          cncTemp[7] = '1'; // 原始数据
          cncTemp[8] = temp[10]; // 工件总数量
          cnc[jiagongjianshu++] = cncTemp;
        }
        else
        {
          temp[15] = "";
          temp[16] = "";
          temp[17] = "0";
          temp[18] = "5"; // 直接进入组装状态
        }
        data[gongjianzongshu++] = temp;
      }
      sql = "select * from machining_sheet where union_order = '"+ order +"'";
      let succ3 = await db_util.query(sql);
      if( succ3.length == 0 || addAll == false )
      {
        sql = "insert into machining_sheet (union_order, type, sheet_order, size_length, size_width, size_height, material_no, stuff, density, quatity, quatity_total, weight, material_issuer, picking_man, bom_remark, cnc_name, stuff2, type_flag, status) values ?";
        let succ = await db_util.query(sql, [data]);
        if( succ.affectedRows  > 0 )
        {
          if( cnc.length > 0 )
          {
            sql = "insert into dispatch_sheet (union_order, name, factory, ljmc, tzcc, czhi, zhl, rawdata, gjsl) values ?";
            let succ2 = await db_util.query(sql, [cnc]);
            if( succ2.affectedRows > 0 )
            {
              setTimeout(function() { ParsePdfFile(order, order, imageNo); }, 1000);
              console.log('ParseBOMFile succeeded.');
            }
            else
            {
              sql = "delete from machining_sheet where union_order = '" + order + "'";
              await db_util.query(sql);
              console.log('ParseBOMFile failed to insert dispatch sheet ~');
              ret = "failed to insert dispatch sheet ~";
            }
          }
        }
        else
        {
          console.log('ParseBOMFile failed to insert sheet table, so delete order from union sheet table');
          ret = "failed to insert sheet table";
        }
      }
      else
      {
        gongjianzongshu = 0;
        var temp = new Array(); // 表machining_sheet中已更新的记录ID
        for(k=0; k<data.length; k++)
        {
          for(j=0; j<succ3.length; j++)
          {
            if( succ3[j].sheet_order == data[k][2] )
            {
              gongjianzongshu ++;
              temp.push(succ3[j].id);

              if( data[k][17] == "1" ) // 加工件
              {
                sql = "update machining_sheet set size_length = '"+ data[k][3] +"', size_width = '"+ data[k][4] +"', size_height = '"+ data[k][5] +"',\
                      material_no = '"+ data[k][6] +"', stuff = '"+ data[k][7] +"', density = '"+ data[k][8] +"', quatity = '"+ data[k][9] +"',\
                      quatity_total = '"+ data[k][10] +"', weight = '"+ data[k][11] +"', material_issuer = '"+ data[k][12] +"',\
                      picking_man = '"+ data[k][13] +"', bom_remark = '"+ data[k][14] +"', bianchengriqi = '', code_end_date = '' where id = '"+ succ3[j].id +"'";
              }
              else
              {
                sql = "update machining_sheet set material_no = '"+ data[k][6] +"', quatity = '"+ data[k][9] +"', quatity_total = '"+ data[k][10] +"',\
                      material_issuer = '"+ data[k][12] +"', picking_man = '"+ data[k][13] +"', bom_remark = '"+ data[k][14] +"' where id = '"+ succ3[j].id +"'";
              }
              await db_util.query(sql);
              if( data[k][17] == "1" ) // 加工件，更新dispatch_sheet
              {
                for(j=0; j<cnc.length; j++)
                {
                  if( cnc[j][3] == data[k][2] )
                  {
                    sql = "update dispatch_sheet set name = '"+ name +"', factory = '"+ factory +"', tzcc = '"+ cnc[j][4] +"',\
                          czhi = '"+ cnc[j][5] +"', zhl = '"+ cnc[j][6] +"', gjsl = '"+ cnc[j][8] +"' where union_order = '"+ order +"' and ljmc = '"+ cnc[j][3] +"'";
                    await db_util.query(sql);
                    break;
                  }
                }
              }
              break;
            }
          }
          if( j == succ3.length ) // 新增的记录
          {
            sql = "insert into machining_sheet (union_order, type, sheet_order, size_length, size_width, size_height, material_no, stuff, density, quatity, quatity_total, weight, material_issuer, picking_man, bom_remark, cnc_name, stuff2, type_flag, status) values (\
                  '"+ data[k][0] +"', '"+ data[k][1] +"', '"+ data[k][2] +"', '"+ data[k][3] +"', '"+ data[k][4] +"', '"+ data[k][5] +"',\
                  '"+ data[k][6] +"', '"+ data[k][7] +"', '"+ data[k][8] +"', '"+ data[k][9] +"', '"+ data[k][10] +"', '"+ data[k][11] +"',\
                  '"+ data[k][12] +"', '"+ data[k][13] +"', '"+ data[k][14] +"', '"+ data[k][15] +"', '"+ data[k][16] +"', '"+ data[k][17] +"', '"+ data[k][18] +"'";
            await db_util.query(sql);
            if( data[k][17] == "1" ) // 加工件
            {
              for(j=0; j<cnc.length; j++)
              {
                if( cnc[j][3] == data[k][2] )
                {
                  sql = "insert into dispatch_sheet (union_order, name, factory, ljmc, tzcc, czhi, zhl, rawdata, gjsl) values (\
                        '"+ order +"', '"+ name +"', '"+ factory +"', '"+ cnc[j][3] +"', '"+ cnc[j][4] +"', '"+ cnc[j][5] +"',\
                        '"+ cnc[j][6] +"', '"+ cnc[j][7] +"', '"+ cnc[j][8] +"')";
                  await db_util.query(sql);
                  break;
                }
              }
            }
            gongjianzongshu ++;
          }
        }
        if( temp.length < succ3.length ) // 还存在旧记录在新表中没有，是否需要删除呢？
        {
          console.log('ParseBOMFile，大表小表中有旧的记录需要删除吗？');
          for(j=0; j<succ3.length; j++)
          {
            for(k=0; k<temp.length; k++)
            {
              if( temp[k] == succ3[j].id )
                break;
            }
            if( k == temp.length )
            {
              sql = "delete from machining_sheet where id = '"+ succ3[j].id +"'";
              console.log(sql);
              sql = "delete from dispatch_sheet where union_order = '"+ order +"' and ljmc = '"+ succ3[j].sheet_order +"'";
              console.log(sql);
            }
          }
        }
        if( gongjianzongshu > 0 )
        {
          setTimeout(function() { ParsePdfFile(order, order, imageNo); }, 1000);
          console.log('ParseBOMFile succeeded to update sheet table.');
        }
      }
    }
    return ret;
  }
  catch(error)
  {
    console.log('ParseBOMFile error: ' + error.message);
    console.log('SQL: ' + sql);
    /*if( order.length > 0 )
    {
      sql = "delete from machining_sheet where union_order = '" + order + "'";
      await db_util.query(sql);
      sql = "delete from machining_union_sheet where union_order = '" + order + "'";
      await db_util.query(sql);
    }*/
    return error.message;
  }
}

app.post('/ParseBOMFile',  async (req, res) => {
  var bomFile = req.body.filepath;
  if(bomFile == undefined)
  {
    res.status(200);
    res.json({"result":"error", "description":"filepath is not set"});
    return;
  }
  try
  {
    var result = "not support this function";
    if( req.body.tryagain == 'yes' )
      result = await ParseBOMFile(bomFile);
    var json = {};
    if( result == 'ok' )
    {
      json["result"] = "ok";
    }
    else
    {
      json["result"] = "error";
      json["description"] = result;
    }
    res.status(200);
    res.json(json);
  }
  catch(error)
  {
    console.log('ParseBOMFile failed, error: ' + error.message);
    var json = {};
    json["result"] = "error";
    json["description"] = error.message;
    res.status(200);
    res.json(json);
  }
})

app.post('/AddCncInfo', async (req,res) => {
  var body = req.body;
  var sql = "select * from cnc where name = '"+ body.name +"' OR MachineName = '"+ body.MachineName +"' OR MachineSN = '"+ body.MachineSN +"'";
  try
  {
    let rows = await db_util.query(sql);
    if( rows.length > 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":"名称或设备名称或设备序列号已存在"});
      return;
    }
    sql = "insert into cnc (name, MachineName, MachineModel, MachineSN) values('"+ body.name +"', '"+ body.MachineName +"', '"+ body.MachineModel +"', '"+ body.MachineSN +"')";
    let sucData = await db_util.query(sql);
    if( sucData.affectedRows > 0 )
    {
      var json = {};
      json["id"] = sucData.insertId;
      json["name"] = body.name;
      json["diameter_max"] = 0;
      json["length_max"] = 0;
      json["width_max"] = 0;
      json["stuff_type"] = "";
      json["stuff_range"] = "";
      json["remark"] = "";
      json["loading"] = 0;
      json["reserved1"] = "";
      json["reserved2"] = "";
      json["MachineName"] = body.MachineName;
      json["MachineModel"] = body.MachineModel;
      json["MachineSN"] = body.MachineSN;
      json["lastmode"] = "";
      json["lastmode_starttime"] = "";
      json["lastmode_lasttime"] = "";
      g_cncInfo.push(json);
    }
    var date = new Date();
    var month = getMonthDayTime(date);
    var sql = "delete from cncmonth where month = '"+ month +"'";
    await db_util.query(sql);
    sql = "delete from currentmonth where month = '"+ month +"'";
    await db_util.query(sql);

    res.status(200);
    if( sucData.affectedRows > 0 )
      res.json({"result":"ok"});
    else
      res.json({"result":"error"});
    console.log("AddCncInfo return id = " + sucData.insertId);
  }
  catch(error)
  {
    console.log('Failed to AddCncInfo: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateCncInfo',function(req,res){
  var body = req.body;
  var flag = false;
  var sql = "Update cnc set ";
  var where = "";
  if( body.id == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"the id is not found"});
    return;
  }
  else
  {
    where = " where id = '"+ body.id +"'";
  }
  if( body.name != undefined )
  {
    for(var i=0; i<g_cncInfo.length; i++)
    {
      if( g_cncInfo[i].id == body.id )
        continue;
      if( g_cncInfo[i].name == body.name )
      {
        res.status(200);
        res.json({"result":"error", "description":"名称已存在"});
        return;
      }
    }
    if(flag)
      sql += ", ";
    sql += "name = '"+ body.name +"'";
    flag = true;
  }
  if( body.diameter_max != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "diameter_max = '"+ body.diameter_max +"'";
    flag = true;
  }
  if( body.length_max != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "length_max = '"+ body.length_max +"'";
    flag = true;
  }
  if( body.width_max != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "width_max = '"+ body.width_max +"'";
    flag = true;
  }
  if( body.stuff_type != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "stuff_type = '"+ body.stuff_type +"'";
    flag = true;
  }
  if( body.stuff_range != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "stuff_range = '"+ body.stuff_range +"'";
    flag = true;
  }
  if( body.remark != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "remark = '"+ body.remark +"'";
    flag = true;
  }
  if( body.MachineName != undefined )
  {
    for(var i=0; i<g_cncInfo.length; i++)
    {
      if( g_cncInfo[i].id == body.id )
        continue;
      if( g_cncInfo[i].MachineName == body.MachineName )
      {
        res.status(200);
        res.json({"result":"error", "description":"设备名称已存在"});
        return;
      }
    }
    if(flag)
      sql += ", ";
    sql += "MachineName = '"+ body.MachineName +"'";
    flag = true;
  }
  if( body.MachineModel != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "MachineModel = '"+ body.MachineModel +"'";
    flag = true;
  }
  if( body.MachineSN != undefined )
  {
    for(var i=0; i<g_cncInfo.length; i++)
    {
      if( g_cncInfo[i].id == body.id )
        continue;
      if( g_cncInfo[i].MachineSN == body.MachineSN )
      {
        res.status(200);
        res.json({"result":"error", "description":"设备序列号已存在"});
        return;
      }
    }
    if(flag)
      sql += ", ";
    sql += "MachineSN = '"+ body.MachineSN +"'";
    flag = true;
  }
  if( body.MachineNO != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "MachineNO = '"+ body.MachineNO +"'";
    flag = true;
  }
  if( body.guid != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "guid = '"+ body.guid +"'";
    flag = true;
  }
  if( body.Plant != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "Plant = '"+ body.Plant +"'";
    flag = true;
  }
  if( body.Dept != undefined )
  {
    if(flag)
      sql += ", ";
    sql += "Dept = '"+ body.Dept +"'";
    flag = true;
  }
  if(flag)
  {
    sql += where;
    //console.log(sql);
    db_util.ExecuteSQL(sql, null,
      (sucData) => 
      {
        for(var i=0; i<g_cncInfo.length; i++)
        {
          if( g_cncInfo[i].id == body.id )
          {
            if( body.name != undefined )
              g_cncInfo[i].name = body.name;
            if( body.diameter_max != undefined )
              g_cncInfo[i].diameter_max = body.diameter_max;
            if( body.length_max != undefined )
              g_cncInfo[i].length_max = body.length_max;
            if( body.width_max != undefined )
              g_cncInfo[i].width_max = body.width_max;
            if( body.stuff_type != undefined )
              g_cncInfo[i].stuff_type = body.stuff_type;
            if( body.stuff_range != undefined )
              g_cncInfo[i].stuff_range = body.stuff_range;
            if( body.remark != undefined )
              g_cncInfo[i].remark = body.remark;
            if( body.MachineName != undefined )
              g_cncInfo[i].MachineName = body.MachineName;
            if( body.MachineModel != undefined )
              g_cncInfo[i].MachineModel = body.MachineModel;
            if( body.MachineSN != undefined )
              g_cncInfo[i].MachineSN = body.MachineSN;
            if( body.MachineNO != undefined )
              g_cncInfo[i].MachineNO = body.MachineNO;
            if( body.guid != undefined )
              g_cncInfo[i].guid = body.guid;
            if( body.Plant != undefined )
              g_cncInfo[i].Plant = body.Plant;
            if( body.Dept != undefined )
              g_cncInfo[i].Dept = body.Dept;
            break;
          }
        }
        console.log(sucData.message);
        res.status(200);
        if( sucData.affectedRows > 0)
          res.json({"result":"ok", "changedRows":sucData.changedRows});
        else
          res.json({"result":"error", "description":"not find the record"});
      },
      (errData) =>
      {
        res.status(200);
        res.json({"result":"error", "description":errData.message});
        console.log('Failed: ' + sql);
      }
    );
  }
  else
  {
    res.status(200);
    res.json({"result":"error", "description":"no column was matched to update"});
    console.log('Failed, no column was matched to update');
  }
})

app.post('/DeleteCncInfo', async (req,res) => {
  if( req.body.id == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set parameter of id"});
    return;
  }
  var sql = "delete from cnc where id = '" + req.body.id +"'";
  try
  {
    let result = await db_util.query(sql);
    if( result.affectedRows > 0 )
    {
      for(var i=0; i<g_cncInfo.length; i++)
      {
        if( g_cncInfo[i].id == req.body.id )
        {
          g_cncInfo.splice(i, 1);
          break;
        }
      }
    }
    var date = new Date();
    var month = getMonthDayTime(date);
    var sql = "delete from cncmonth where month = '"+ month +"'";
    await db_util.query(sql);
    sql = "delete from currentmonth where month = '"+ month +"'";
    await db_util.query(sql);

    res.status(200);
    if( result.affectedRows > 0 )
      res.json({"result":"ok"});
    else
      res.json({"result":"error", "description":"no row data matched the id"});
  }
  catch(error)
  {
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryCncData', async (req, res) => {
  var body = req.body;
  var sql = "select * from dispatch_sheet";
  if( body.cnc == undefined )
  {
    if( body.unionorder == undefined )
    {
    }
    else if( body.unionorder.length > 0 )
    {
      sql += " where union_order = '"+ body.unionorder +"'";
      if( body.sheetorder != undefined )
        sql += " and ljmc = '"+ body.sheetorder +"'";
    }
  }
  else
  {
    if( body.unionorder == undefined )
    {
      if( body.cnc.length > 0 )
        sql += " where cnc like '%"+ body.cnc +"%'"
    }
    else
    {
      if( body.unionorder.length > 0 )
      {
        if( body.cnc.length > 0 )
          sql += " where union_order = '"+ body.unionorder +"' and cnc like '%"+ body.cnc +"%'";
        else
          sql += " where union_order = '"+ body.unionorder +"'";
      }
      else if( body.cnc.length > 0 )
      {
        sql += " where cnc like '%"+ body.cnc +"%'"
      }
    }
  }
  if( body.box != undefined )
  {
    if( body.box.length > 0 )
    {
      if( sql.indexOf('where') > 0 )
        sql += " and box like '%"+ body.box +"%'";
      else
        sql += " where box like '%"+ body.box +"%'";
    }
  }
  if( body.flag != undefined )
  {
    if( sql.indexOf('where') > 0 )
      sql += " and rawdata = '"+ body.flag +"'";
    else
      sql += " where rawdata = '"+ body.flag +"'";
  }
  var status = -1;
  if( body.status != undefined )
  {
    //console.log('body.status: **** ' + parseInt(body.status));
    status = parseInt(body.status);
    if( isNaN(status) )
      status = -1;
  }
  if( body.order != undefined )
  {
    sql += " "+ body.order +"";
  }
  console.log(sql + ' --- status = ' + status + ', banci = ' + body.banci);
  try
  {
    let sucData = await db_util.query(sql);
    let suc = await db_util.query("select id, union_order, sheet_order, material_no, quatity_total, stuff, status, imagefile, banci, banci2 from machining_sheet");
    var json = {};
    var array = new Array();
    sucData.forEach(element => {
      for(var i=0; i<suc.length; i++)
      {
        if( suc[i].union_order == element.union_order && suc[i].sheet_order == element.ljmc )
        {
          element["gjsl"] = suc[i].quatity_total;
          element["czhi"] = suc[i].stuff;
          element["material_no"] = suc[i].material_no;
          element["imagefile"] = suc[i].imagefile;
          if( status < 0 || suc[i].status == status )
          {
            if( body.banci == undefined || body.banci == '' )
            {
              array.push(element);
            }
            else
            {
              if( status == 1 ) // 编程
              {
                if( body.banci == suc[i].banci2 )
                {
                  array.push(element);
                }
              }
              else if( status == 2 ) // 加工
              {
                if( body.banci == '' || body.banci == suc[i].banci )
                {
                  array.push(element);
                }
              }
              else
              {
                array.push(element);
              }
            }
          }
          break;
        }
      }
    });
    json["result"] = "ok";
    json["order"] = array;
    res.status(200);
    res.json(json);
  }
  catch(error)
  {
    console.log('QueryCncData exception: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddCncData',function(req,res){
  var body = req.body;
  var col = "";
  var val = "";
  if(body.unionorder == undefined || body.name == undefined || body.factory == undefined || body.ljmc == undefined)
  {
    res.status(200);
    res.json({"result":"error", "description":"unionorder or name or factory or ljmc is not found"});
    return;
  }
  if(body.cxmc != undefined)
  {
    col += ", cxmc";
    val += ", '"+body.cxmc+"'";
  }
  if(body.tdgd != undefined)
  {
    col += ", tdgd";
    val += ", '"+body.tdgd+"'";
  }
  if(body.ygsj != undefined)
  {
    col += ", ygsj";
    val += ", '"+body.ygsj+"'";
  }
  if(body.czhi != undefined)
  {
    col += ", czhi";
    val += ", '"+body.czhi+"'";
  }
  if(body.zhl != undefined)
  {
    col += ", zhl";
    val += ", '"+body.zhl+"'";
  }
  if(body.tzcc != undefined)
  {
    col += ", tzcc";
    val += ", '"+body.tzcc+"'";
  }
  if(body.djxq != undefined)
  {
    col += ", djxq";
    val += ", '"+body.djxq+"'";
  }
  if(body.zjfs != undefined)
  {
    col += ", zjfs";
    val += ", '"+body.zjfs+"'";
  }
  if(body.jgyd != undefined)
  {
    col += ", jgyd";
    val += ", '"+body.jgyd+"'";
  }
  if(body.djqr != undefined)
  {
    col += ", djqr";
    val += ", '"+body.djqr+"'";
  }
  if(body.jcqj != undefined)
  {
    col += ", jcqj";
    val += ", '"+body.jcqj+"'";
  }
  if(body.dpdw != undefined)
  {
    col += ", dpdw";
    val += ", '"+body.dpdw+"'";
  }
  if(body.mcqj != undefined)
  {
    col += ", mcqj";
    val += ", '"+body.mcqj+"'";
  }
  if(body.cxycclsj != undefined)
  {
    col += ", cxycclsj";
    val += ", '"+body.cxycclsj+"'";
  }
  if(body.dbjz != undefined)
  {
    col += ", dbjz";
    val += ", '"+body.dbjz+"'";
  }
  if(body.zjbs != undefined)
  {
    col += ", zjbs";
    val += ", '"+body.zjbs+"'";
  }
  if(body.zjzgs != undefined)
  {
    col += ", zjzgs";
    val += ", '"+body.zjzgs+"'";
  }
  if(body.cncsj != undefined)
  {
    col += ", cncsj";
    val += ", '"+body.cncsj+"'";
  }
  if(body.xlcc_x != undefined)
  {
    col += ", xlcc_x";
    val += ", '"+body.xlcc_x+"'";
  }
  if(body.xlcc_y != undefined)
  {
    col += ", xlcc_y";
    val += ", '"+body.xlcc_y+"'";
  }
  if(body.xlcc_z != undefined)
  {
    col += ", xlcc_z";
    val += ", '"+body.xlcc_z+"'";
  }
  if(body.xlcc_bs != undefined)
  {
    col += ", xlcc_bs";
    val += ", '"+body.xlcc_bs+"'";
  }
  if(body.xlcc_pb != undefined)
  {
    col += ", xlcc_pb";
    val += ", '"+body.xlcc_pb+"'";
  }
  if(body.yjjg != undefined)
  {
    col += ", yjjg";
    val += ", '"+body.yjjg+"'";
  }
  if(body.gjsl != undefined)
  {
    col += ", gjsl";
    val += ", '"+body.gjsl+"'";
  }
  if(body.blps != undefined)
  {
    col += ", blps";
    val += ", '"+body.blps+"'";
  }
  if(body.bcry != undefined)
  {
    col += ", bcry";
    val += ", '"+body.bcry+"'";
  }
  if(body.bzhu != undefined)
  {
    col += ", bzhu";
    val += ", '"+body.bzhu+"'";
  }
  if(body.cnc != undefined)
  {
    col += ", cnc";
    val += ", '"+body.cnc+"'";
  }
  if(body.box != undefined)
  {
    col += ", box";
    val += ", '"+body.box+"'";
  }
  col += ", rawdata";
  val += ", '0'"
  var sql = "insert into dispatch_sheet (union_order, name, factory, ljmc" + col + ") values('"+body.unionorder+"', '"+body.name+"', '"+body.factory+"', '"+body.ljmc+"'" + val + ")";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      res.status(200);
      res.json({"result":"ok", "id":sucData.insertId});
      console.log("AddCncData return id = " + sucData.insertId);
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "description":errData.message});
    }
  );
})

app.post('/UpdateCncData',function(req,res){
  var body = req.body;
  var flag = false;
  var sql = "Update dispatch_sheet set ";
  var where = "";
  if( body.id == undefined )
  {
    if( body.unionorder == undefined || body.workorder == undefined )
    {
      res.status(200);
      res.json({"result":"error", "description":"the id or unionorder/workorder is not found"});
      return;
    }
    where = " where union_order = '"+ body.unionorder +"' and ljmc = '"+ body.workorder +"'";
  }
  else
  {
    where = " where id = '"+ body.id +"'";
  }
  if( body.factory != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "factory = '"+body.factory+"'";
    flag = true;
  }
  if( body.cxmc != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "cxmc = '"+body.cxmc+"'";
    flag = true;
  }
  if( body.tdgd != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "tdgd = '"+body.tdgd+"'";
    flag = true;
  }
  if( body.ygsj != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "ygsj = '"+body.ygsj+"'";
    flag = true;
  }
  if( body.czhi != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "czhi = '"+body.czhi+"'";
    flag = true;
  }
  if( body.zhl != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "zhl = '"+body.zhl+"'";
    flag = true;
  }
  if( body.tzcc != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "tzcc = '"+body.tzcc+"'";
    flag = true;
  }
  if( body.djxq != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "djxq = '"+body.djxq+"'";
    flag = true;
  }
  if( body.zjfs != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "zjfs = '"+body.zjfs+"'";
    flag = true;
  }
  if( body.jgyd != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "jgyd = '"+body.jgyd+"'";
    flag = true;
  }
  if( body.djqr != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "djqr = '"+body.djqr+"'";
    flag = true;
  }
  if( body.jcqj != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "jcqj = '"+body.jcqj+"'";
    flag = true;
  }
  if( body.dpdw != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "dpdw = '"+body.dpdw+"'";
    flag = true;
  }
  if( body.mcqj != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "mcqj = '"+body.mcqj+"'";
    flag = true;
  }
  if( body.cxycclsj != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "cxycclsj = '"+body.cxycclsj+"'";
    flag = true;
  }
  if( body.dbjz != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "dbjz = '"+body.dbjz+"'";
    flag = true;
  }
  if( body.zjbs != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "zjbs = '"+body.zjbs+"'";
    flag = true;
  }
  if( body.zjzgs != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "zjzgs = '"+body.zjzgs+"'";
    flag = true;
  }
  if( body.cncsj != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "cncsj = '"+body.cncsj+"'";
    flag = true;
  }
  if( body.xlcc_x != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "xlcc_x = '"+body.xlcc_x+"'";
    flag = true;
  }
  if( body.xlcc_y != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "xlcc_y = '"+body.xlcc_y+"'";
    flag = true;
  }
  if( body.xlcc_z != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "xlcc_z = '"+body.xlcc_z+"'";
    flag = true;
  }
  if( body.xlcc_bs != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "xlcc_bs = '"+body.xlcc_bs+"'";
    flag = true;
  }
  if( body.xlcc_pb != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "xlcc_pb = '"+body.xlcc_pb+"'";
    flag = true;
  }
  if( body.yjjg != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "yjjg = '"+body.yjjg+"'";
    flag = true;
  }
  if( body.gjsl != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "gjsl = '"+body.gjsl+"'";
    flag = true;
  }
  if( body.blps != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "blps = '"+body.blps+"'";
    flag = true;
  }
  if( body.bcry != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "bcry = '"+body.bcry+"'";
    flag = true;
  }
  if( body.bzhu != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "bzhu = '"+body.bzhu+"'";
    flag = true;
  }
  if( body.cnc != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "cnc = '"+body.cnc+"'";
    flag = true;
  }
  if( body.box != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "box = '"+body.box+"'";
    flag = true;
  }
  if( body.status != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "status = '"+body.status+"'";
    flag = true;
  }
  if( body.remark != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "remark = '"+body.remark+"'";
    flag = true;
  }
  if( body.songjian_shuliang != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "songjian_shuliang = '"+body.songjian_shuliang+"'";
    flag = true;
  }
  if( body.songjian_shijian != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "songjian_shijian = '"+body.songjian_shijian+"'";
    flag = true;
  }
  if( body.gzsj_tongji != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "gzsj_tongji = '"+body.gzsj_tongji+"'";
    flag = true;
  }
  if( body.gjjcjg != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "gjjcjg = '"+body.gjjcjg+"'";
    flag = true;
  }
  if( body.pinjian_bzhu != undefined)
  {
    if(flag)
      sql += ", ";
    sql += "pinjian_bzhu = '"+body.pinjian_bzhu+"'";
    flag = true;
  }
  if( body.lingliao_ren != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_ren = '"+ body.lingliao_ren +"'";
    flag = true;
  }
  if( body.lingliao_riqi != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_riqi = '"+ body.lingliao_riqi +"'";
    flag = true;
  }
  if( body.lingliao_qixian != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_qixian = '"+ body.lingliao_qixian +"'";
    flag = true;
  }
  if( body.lingliao_bzhu != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "lingliao_bzhu = '"+ body.lingliao_bzhu +"'";
    flag = true;
  }
  if( body.xuhao != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "xuhao = '"+ body.xuhao +"'";
    flag = true;
  }
  if( body.yibei_shuliang != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "yibei_shuliang = '"+ body.yibei_shuliang +"'";
    flag = true;
  }
  if( body.tuiku_shuliang != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "tuiku_shuliang = '"+ body.tuiku_shuliang +"'";
    flag = true;
  }
  if( body.beiliao_ztai != undefined )
  {
    if( flag )
      sql += ", ";
    sql += "beiliao_ztai = '"+ body.beiliao_ztai +"'";
    flag = true;
  }
  if(flag)
  {
    sql += where;
    console.log(sql);
    db_util.ExecuteSQL(sql, null,
      (sucData) => 
      {
        //console.log(sucData.message);
        if( body.box != undefined )
        {
          if( body.id != undefined )
            sql = "select union_order, ljmc from dispatch_sheet where id = '"+ body.id +"'";
          else
            sql = "select union_order, ljmc from dispatch_sheet where union_order = '"+ body.unionorder +"' and ljmc = '"+ body.workorder +"'";
          db_util.ExecuteSQL(sql, null,
            (suc2) =>
            {
              sql = "update machining_sheet set box = '"+body.box+"' where union_order = '"+suc2[0].union_order+"' and sheet_order = '"+suc2[0].ljmc+"'";
              db_util.ExecuteSQL(sql, null,
                (suc3) =>
                {
                  //console.log('更新排工单表、加工单表的箱号成功');
                  res.status(200);
                  res.json({"result":"ok", "changedRows":sucData.changedRows});
                },
                (err3) =>
                {
                  console.log('更新加工单表的箱号失败');
                  res.status(200);
                  res.json({"result":"ok", "changedRows":sucData.changedRows});
                }
              );
            },
            (err2) =>
            {
              console.log('查询排工单表失败，id=' + body.id + ', ' + err2.message);
              res.status(200);
              res.json({"result":"ok", "changedRows":sucData.changedRows});
            }
          );
        }
        else
        {
          res.status(200);
          if( sucData.affectedRows > 0)
            res.json({"result":"ok", "changedRows":sucData.changedRows});
          else
            res.json({"result":"error", "description":"not find the record"});
        }
      },
      (errData) =>
      {
        res.status(200);
        res.json({"result":"error", "description":errData.message});
        console.log('Failed: ' + sql);
      }
    );
  }
  else
  {
    res.status(200);
    res.json({"result":"error", "description":"no column was matched to update"});
    console.log('Failed, no column was matched to update');
  }
})

app.post('/RejectCncData',function(req,res){
  var body = req.body;
  var sql = "select remark from machining_sheet where union_order = '"+ body.unionorder +"' and sheet_order = '"+ body.workorder +"'";
  db_util.ExecuteSQL(sql, null,
    (suc1) =>
    {
      var newremark = "";
      if( suc1.length > 0 )
        newremark = suc1[0].remark;
      newremark += body.remark;
      sql = "update machining_sheet set remark = '"+ newremark +"' where union_order = '"+ body.unionorder +"' and sheet_order = '"+ body.workorder +"'";
      db_util.ExecuteSQL(sql, null,
        (suc2) =>
        {
          console.log('排工单退回成功了：' + body.unionorder + ' - ' + body.workorder);
          sql = "update dispatch_sheet set remark = '"+ body.remark +"' where union_order = '"+ body.unionorder +"' and ljmc = '"+ body.workorder +"'";
          db_util.ExecuteSQL(sql, null,
            (suc3) =>
            {
              res.status(200);
              res.json({"result":"ok"});
            },
            (err3) =>
            {
              console.log('排工表备注更新有点问题：' + err3.message);
              res.status(200);
              res.json({"result":"ok"});
            }
          );
        },
        (err2) =>
        {
          console.log('排工单退回失败了：' + body.unionorder + ' - ' + body.workorder + ', ' + err2.message);
          res.status(200);
          res.json({"result":"error"});
        }
      );
    },
    (err1) =>
    {
      console.log('排工单退回失败了：' + body.unionorder + ' - ' + body.workorder + ', ' + err1.message);
      res.status(200);
      res.json({"result":"error"});
    }
  );
})

app.post('/DeleteCncData',function(req,res){
  var sql = "select rawdata from dispatch_sheet where id = '" + req.body.id +"'";
  db_util.ExecuteSQL(sql, null,
    (suc1) =>
    {
      if( suc1.length > 0 )
      {
        if( suc1[0].rawData == '0' ) // 非原始数据才可以删除
        {
          sql = "delete from dispatch_sheet where id = '" + req.body.id +"'";
          db_util.ExecuteSQL(sql, null,
            (sucData) =>
            {
              res.status(200);
              if(sucData.affectedRows>0)
                res.json({"result":"ok"});
              else
                res.json({"result":"ok", "description":"not find the id"});
              console.log('Succeeded: ' + sql);
            },
            (errData) =>
            {
              res.status(200);
              res.json({"result":"error", "description":errData.message});
              console.log(errData.message);
            }
          );
        }
        else
        {
          res.status(200);
          res.json({"result":"error", "description":"cannot delete raw data"});
          console.log("cannot delete raw data: " + req.body.id);
        }
      }
      else
      {
        res.status(200);
        res.json({"result":"error", "description":"not find the id"});
        console.log("DeleteCndData failed");
      }
    },
    (err1) =>
    {
      res.status(200);
      res.json({"result":"error", "description":err1.message});
      console.log(err1.message);
    }
  );
})

app.post('/QueryCncAdjustTime',function(req,res){
  var sql = "select * from cnctime";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      var json = {};
      var array = new Array();
      if( sucData.length > 0 )
      {
        sucData.forEach(element => {
          array.push(element);
        });
      }
      json["result"] = "ok";
      json["order"] = array;
      res.status(200);
      res.json(json);
      console.log('query cncAdjustTime data: ' + array.length);
    },
    (errData) =>
    {
      console.log(errData.message);
      res.status(200);
      json["result"] = "error";
      json["errorCode"] = "1";
      json["description"] = errData.message;
      res.json(json);
    }
  );
})

app.post('/AddCncAdjustTime',function(req,res){
  var body = req.body;
  if( body.starttime == undefined || body.starttime == 'null' || body.endtime == undefined || body.endtime == 'null' )
  {
    res.status(200);
    res.json({"result":"error", "description":"starttime or endtime not set"});
    return;
  }
  var sql = "insert into cnctime values(null, '"+ body.starttime +"', '"+ body.endtime +"', '"+ body.status +"', '"+ body.hours +"')";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      res.status(200);
      res.json({"result":"ok"});
      console.log("AddCncAdjustTime return id = " + sucData.insertId);
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "description":errData.message});
    }
  );
})

app.post('/UpdateCncAdjustTime',function(req,res){
  var body = req.body;
  var sql = "Update cnctime set starttime = '"+ body.starttime +"', endtime = '"+ body.endtime +"', status = '"+ body.status +"', hours = '"+ body.hours +"' where id = '"+ body.id +"'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) => 
    {
      console.log(sucData.message);
      res.status(200);
      res.json({"result":"ok", "description":sucData.message});
    },
    (errData) =>
    {
        res.status(200);
        res.json({"result":"error", "errorCode": "1", "description": errData.message}) ;
    }
  );
})

app.post('/DeleteCncAdjustTime',function(req,res){
  var sql = "delete from cnctime where id = '" + req.body.id +"'";
  db_util.ExecuteSQL(sql, null,
    (sucData) =>
    {
      res.status(200);
      if(sucData.affectedRows>0)
        res.json({"result":"ok"});
      else
        res.json({"result":"ok", "description":"not find the id"});
      console.log('Succeeded: ' + sql);
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "description":errData.message});
      console.log(errData.message);
    }
  );
})

function mkdirSync(filePath)
{
  if( fs.existsSync(filePath) )
    return true;
  if(mkdirSync(path.dirname(filePath)))
  {
    fs.mkdirSync(filePath);
    return true;
  }
}

app.post('/Upload', async (req, res) => {
  var body =  req.body;
  if(body.unionorder == undefined || body.workorder == undefined || body.filename == undefined || body.filedata == undefined)
  {
    if( body.unionorder == undefined )
      console.log('Upload failed, unionorder is null');
    else if( body.workorder == undefined )
      console.log('Upload failed, workorder is null');
    else if( body.fileName == undefined )
      console.log('Upload failed, filename is null');
    else
      console.log('Upload failed, filedata is null');
    res.status(200);
    res.json({"result":"error", "description":"unionorder or workorder or filename or filedata is not set"});
    return;
  }
  else
  {
    console.log("请求上传 " + body.unionorder + "/" + body.filename + " (" + body.filedata.length + " bytes)");
  }
  var date = new Date();
  var filePath = "./public/" + body.unionorder;
  mkdirSync(filePath);
  filePath += '/';
  filePath += body.filename;
  var responseBody = {};
  try
  {
    var rawData = body.filedata;
    var index = rawData.indexOf("base64,");
    if( index < 5 )
    {
      console.log('Failed to upload, not a base64 file: ' + body.filename);
      res.status(200);
      res.json({"result":"error", "description":"not find base64 flag"});
      return;
    }
    index += 7;
    var base64Data = rawData.substr(index);
    var data = Buffer.from(base64Data, 'base64');
    fs.writeFileSync(filePath, data);
    console.log('file saved' + " (" + data.length + " bytes)");

    let ret = await CheckBOMFile(filePath, body.unionorder);
    if( ret.length > 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":ret});
      return;
    }
    var upload_time = getMonthDayTime(date, 1, 1);
    var sql = "select * from machining_files where union_order = '" + body.unionorder + "' and sheet_order = '" + body.workorder +"' and file_path = '" + filePath + "'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
      sql = "insert into machining_files (union_order, sheet_order, file_path, file_name, upload_time, file_status) values('"+ body.unionorder + "', '" + body.workorder + "', '" + filePath + "', '" + body.filename +"', '"+ upload_time +"', '0')";
    else
      sql = "update machining_files set upload_time = '"+ upload_time +"', file_status = '0' where id = "+ suc[0].id +"";
    let sucData = await db_util.query(sql);
    if( body.unionorder == "warehouse" )
    {
      let array = await ParseWarehouseFile(filePath);
      res.status(200);
      res.json({"result":"ok", "order":array});
    }
    else
    {
      if( suc.length == 0 )
      {
        sql = "select id, imagefile from machining_sheet where union_order = '"+ body.unionorder +"' and sheet_order = '"+ body.workorder +"'";
        let succ2 = await db_util.query(sql);
        if( succ2.length > 0 )
        {
          filePath = "";
          if( succ2[0].imagefile != '' )
          {
            filePath = succ2[0].imagefile + ',';
          }
          filePath += body.unionorder;
          filePath += '/';
          filePath += body.filename;
          sql = "update machining_sheet set imagefile = '"+ filePath +"' where id = '"+ succ2[0].id +"'";
          await db_util.query(sql);
        }
      }
      res.status(200);
      res.json({"result":"ok", "id":sucData.insertId});
    }
  }
  catch(error)
  {
    console.log("上传出错: " + error.message);
    responseBody = JSON.stringify({result:"error", description:error.message});
    res.status(200).end(responseBody.toString());
  }
})

app.post('/CollectData', function(req, res){
  var body = req.body;
  var sql = "select id from cncdata where Time = '"+ body.Time +"'";
  db_util.ExecuteSQL(sql, null,
    (suc1) =>
    {
      if( suc1.length == 0 )
      {
        var operatingstatus = "";
        if( body.operatingstatus != undefined )
          operatingstatus = body.operatingstatus;
        var operatingmode = "";
        if( body.operatingmode != undefined )
          operatingmode = body.operatingmode;
        var alarmstatus = "False";
        if( body.Errcode != undefined )
          alarmstatus = body.Errcode;
        else if( body.alarmstatus != undefined )
          alarmstatus = body.alarmstatus;
        var cycletime = "";
        //if( body.cycletime != undefined )
        //  cycletime = body.cycletime;
        var operatingtime = "";
        //if( body.operatingtime != undefined )
        //  operatingtime = body.operatingtime;
        var partcount = "";
        if( body.partcount != undefined )
          partcount = body.partcount;
        var feedrate = "";
        if( body.feedratecmd != undefined )
          feedrate = body.feedratecmd;
        else if( body.feedrate != undefined )
          feedrate = body.feedrate;
        var feedrateoverride = "";
        if( body.feedrateoverride != undefined )
          feedrateoverride = body.feedrateoverride;
        var program = "";
        if( body.program != undefined )
          program = body.program;
        var actualspeed = "";
        if( body.spindlespeedcmd != undefined )
          actualspeed = body.spindlespeedcmd;
        else if( body.actualspeed != undefined )
          actualspeed = body.actualspeed;
        var speedoverride = "";
        if( body.speedoverride != undefined )
          speedoverride = body.speedoverride;
        var activetoolid = "";
        if( body.activetoolid != undefined )
          activetoolid = body.activetoolid;
        if( activetoolid == "" || activetoolid == "0" )
        {
          if( body.toolidcmd != undefined )
            activetoolid = body.toolidcmd;
        }
        sql = "insert into cncdata values(null, '"+body.evt_type+"', '"+body.MachineName+"', '', '"+body.Time+"', '"+body.LocalTime+"', '"+body.Operation_Mode+"', '', '"+operatingstatus+"', '"+operatingmode+"', '"+alarmstatus+"', '"+cycletime+"', '"+operatingtime+"', '"+partcount+"', '"+feedrate+"', '"+feedrateoverride+"', '"+program+"', '"+actualspeed+"', '"+speedoverride+"', '"+activetoolid+"')";
        db_util.ExecuteSQL(sql, null,
          (suc2) =>
          {
            g_lastUpdateTime = Date.now();
            for(var i=0; i<g_cncInfo.length; i++)
            {
              if( g_cncInfo[i].MachineName == body.MachineName )
              {
                if( g_cncInfo[i]["lastmode"] != body.Operation_Mode )
                {
                  g_cncInfo[i]["lastmode"] = body.Operation_Mode;
                  g_cncInfo[i]["lastmode_starttime"] = body.Time;
                }
                g_cncInfo[i]["lastmode_lasttime"] = body.Time;
                break;
              }
            }
            if( (suc2.insertId % 500) == 0 ) // 每500条log一次，每条一次量太大了
              console.log('Succeeded to insert cncdata: ' + body.Time + ' [' + body.LocalTime + '] at ' + suc2.insertId);
            res.status(200);
            res.json({"result":"ok"});
          },
          (err2) =>
          {
            console.log('Failed to insert cncdata: ' + body.Time + ', ' + err2.message);
            res.status(200);
            res.json({"result":"error", "description": (body.Time + ', ' + err2.message)});
          }
        );
      }
      else
      {
        var date = new Date(body.Time);
        console.log('The data exists, id = ' + suc1[0].id + ', Time = ' + body.Time + ' [' + getMonthDayTime(date, 1, 1) + ']');
        res.status(200);
        res.json({"result":"error", "description": "the data existed already"});
      }
    },
    (err1) =>
    {
      console.log('Failed to CollectData ' + body.Time + ', ' + err1.message);
      res.status(200);
      res.json({"result":"error", "description": err1.message});
    }
  );
})

app.post('/CollectDataBlock', async(req, res) => {
  var body = req.body;
  if( body.items == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description": "items is undefined"});
    return;
  }
  var sql = "";
  var operatingstatus = "";
  var operatingmode = "";
  var alarmstatus = "";
  var data = new Array();
  var wait_time = g_nOffTime / 10;
  var i = 0, k = 0;
  for(i=0; i<body.items.length; i++)
  {
    for(k=0; k<data.length; k++)
    {
      if( data[k][2] == body.items[i].MachineName && data[k][1] == body.items[i].evt_type && data[k][6] == body.items[i].Operation_Mode )
      {
        //console.log(body.items[i].MachineName + ' more than 1 times: ' + body.items[i].Time + ', ' + data[k][4]);
        break;
      }
    }
    if( k < data.length )
    {
      continue;
    }
    operatingstatus = "";
    operatingmode = "";
    alarmstatus = "";
    if( body.items[i].operatingstatus != undefined )
      operatingstatus = body.items[i].operatingstatus;
    if( body.items[i].operatingmode != undefined )
      operatingmode = body.items[i].operatingmode;
    if( body.items[i].Errcode != undefined )
      alarmstatus = body.items[i].Errcode;
    else if( body.items[i].alarmstatus != undefined )
      alarmstatus = body.items[i].alarmstatus;
    sql = "select evt_type, Time, Operation_Mode, operatingstatus, operatingmode, alarmstatus from cncdata where MachineName = '"+ body.items[i].MachineName +"' ORDER BY id DESC LIMIT 1";
    let succ2 = await db_util.query(sql);
    if( succ2.length > 0 )
    {
      var lastTime = parseInt(succ2[0].Time);
      var currentTime = parseInt(body.items[i].Time);
      if( currentTime < (lastTime + wait_time) )
      {
        if( succ2[0].evt_type == body.items[i].evt_type && succ2[0].Operation_Mode == body.items[i].Operation_Mode &&
            succ2[0].operatingstatus == operatingstatus && succ2[0].operatingmode == operatingmode && succ2[0].alarmstatus == alarmstatus )
        {
          continue;
        }
      }
    }
    var temp = new Array(20);
    temp[0] = null;
    temp[1] = body.items[i].evt_type;
    temp[2] = body.items[i].MachineName;
    temp[3] = "";//body.items[i].MachineSN;
    temp[4] = body.items[i].Time;
    temp[5] = body.items[i].LocalTime;
    temp[6] = body.items[i].Operation_Mode;
    temp[7] = "";//body.items[i].Spindle_rated_load;
    temp[8] = operatingstatus;
    temp[9] = operatingmode;
    temp[10] = alarmstatus;
    //if( body.items[i].cycletime == undefined )
      temp[11] = "";
    //else
    //  temp[11] = body.items[i].cycletime;
    //if( body.items[i].operatingtime == undefined )
      temp[12] = "";
    //else
    //  temp[12] = body.items[i].operatingtime;
    if( body.items[i].partcount == undefined )
      temp[13] = "";
    else
      temp[13] = body.items[i].partcount;
    if( body.items[i].feedratecmd != undefined )
      temp[14] = body.items[i].feedratecmd;
    else if( body.items[i].feedrate != undefined )
      temp[14] = body.items[i].feedrate;
    else
      temp[14] = "";
    if( body.items[i].feedrateoverride == undefined )
      temp[15] = "";
    else
      temp[15] = body.items[i].feedrateoverride;
    if( body.items[i].program == undefined )
      temp[16] = "";
    else
      temp[16] = body.items[i].program;
    if( body.items[i].spindlespeedcmd != undefined )
      temp[17] = body.items[i].spindlespeedcmd;
    else if( body.items[i].actualspeed != undefined )
      temp[17] = body.items[i].actualspeed;
    else
      temp[17] = "";
    if( body.items[i].speedoverride == undefined )
      temp[18] = "";
    else
      temp[18] = body.items[i].speedoverride;
    if( body.items[i].activetoolid == undefined )
      temp[19] = "";
    else
      temp[19] = body.items[i].activetoolid;
    if( temp[19] == "" || temp[19] == "0" )
    {
      if( body.items[i].toolidcmd != undefined )
        temp[19] = body.items[i].toolidcmd;
    }
    data.push(temp);
    // 这里没有设置当前状态的开始时间
  }
  if( data.length == 0 )
  {
    //console.log('数据忽略：' + body.items.length);
    res.status(200);
    res.json({"result":"ok","lastID":0});
    return;
  }
  sql = "insert into cncdata values ?";
  db_util.ExecuteSQL(sql, [data],
    (suc) =>
    {
      g_lastUpdateTime = Date.now();
      var id = suc.insertId + suc.affectedRows - 1;
      for(var i=suc.insertId; i<=id; i++)
      {
        if( (i % 500) == 0 )
        {
          var date = new Date();
          console.log('Succeeded to insert into cncdata ' + suc.affectedRows + ' values to ' + id + ' on ' + getMonthDayTime(date, 1, 1));
          break;
        }
      }
      res.status(200);
      res.json({"result":"ok","lastID":id});
    },
    (err) =>
    {
      var msg = err.message;
      msg += ('. data from ' + body.items[0].Time + ' to ' + body.items[body.items.length-1].Time);
      console.log('Failed to insert CollectDataBlock: ' + msg);
      res.status(200);
      res.json({"result":"error", "description": msg});
    }
  );
})

app.post('/QueryCncOther', function(req, res){
  var sql = "select * from cncother where name = '"+ req.body.name +"'";
  db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      res.status(200);
      if( suc.length > 0 )
        res.json({"result":"ok", "name": req.body.name, "value": suc[0].value});
      else
        res.json({"result":"error", "description": "not find the matched name"});
    },
    (err) =>
    {
      res.status(200);
      res.json({"result":"error", "description": err.message});
    }
  );
})

app.post('/AddCncOther', function(req, res){
  var sql = "select * from cncother where name = '"+ req.body.name +"'";
  db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      if( suc.length > 0 )
      {
        sql = "update cncother set value = '"+ req.body.value +"' where name = '"+ req.body.name +"'";
        db_util.ExecuteSQL(sql, null,
          (suc2) =>
          {
            res.status(200);
            res.json({"result":"ok", "description": "update the name value"});
          },
          (err2) =>
          {
            res.status(200);
            res.json({"result":"error", "description": err2.message});
          }
        );
      }
      else
      {
        sql = "insert into cncother (name, value) values('"+ req.body.name +"', '"+ req.body.value +"')";
        db_util.ExecuteSQL(sql, null,
          (suc3) =>
          {
            res.status(200);
            res.json({"result":"ok"});
          },
          (err3) =>
          {
            res.status(200);
            res.json({"result":"error", "description": err3.message});
          }
        );
      }
    },
    (err) =>
    {
      res.status(200);
      res.json({"result":"error", "description": err.message});
    }
  );
})

app.post('/UpdateCncOther', function(req, res){
  var sql = "update cncother set value = '"+ req.body.value +"' where name = '"+ req.body.name +"'";
  db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      res.status(200);
      res.json({"result":"ok"});
    },
    (err) =>
    {
      res.status(200);
      res.json({"result":"error", "description": err.message});
    }
  );
})

app.post('/DeleteCncOther', function(req, res){
  var sql = "delete from cncother where name = '"+ req.body.name +"'";
  db_util.ExecuteSQL(sql, null,
    (suc) =>
    {
      res.status(200);
      res.json({"result":"ok"});
    },
    (err) =>
    {
      res.status(200);
      res.json({"result":"error", "description": err.message});
    }
  );
})

app.post('/QueryDeliveryOrder', async (req, res) => {
  try
  {
    let ret = await db_util.query("select * from delivery_sheet");
    res.status(200);
    res.json({"result":"ok","order":ret});
  }
  catch(error)
  {
    console.log('QueryDeliveryOrder failed, ' + error.message);
    res.status(200);
    res.json({"result":"error","description":error.message});
  }
})

app.post('/AddDeliveryOrder', async (req, res) => {
  if( req.body.unionorder == undefined || req.body.quatity == undefined )
  {
    res.status(200);
    res.json({"result":"error","description":"not set unionorder or quatity"});
    return;
  }
  var quatity = parseFloat(req.body.quatity);
  if( quatity <= 0 )
  {
    res.status(200);
    res.json({"result":"error","description":"quatity is less than 0"});
    return;
  }
  try
  {
    var sql = "select name, delivery_addr from machining_union_sheet where union_order = '"+ req.body.unionorder +"'";
    let ret = await db_util.query(sql);
    if( ret.length > 0 )
    {
      sql = "insert into delivery_sheet values('"+ req.body.unionorder +"', '"+ ret[0].name +"', '"+ req.body.quatity +"', '"+ ret[0].delivery_addr +"', '', '', '"+ req.body.lingqu_ren +"')";
      let ret2 = await db_util.query(sql);
    }
    res.status(200);
    if( ret.length > 0 )
      res.json({"result":"ok"});
    else
      res.json({"result":"error", "description":"not find the unionorder"});
  }
  catch(error)
  {
    console.log('AddDeliveryOrder failed, ' + error.message);
    res.status(200);
    res.json({"result":"error","description":error.message});
  }
})

app.post('/UpdateDeliveryOrder', function (req, res) {
  var body = req.body;
  var sql = "Update delivery_sheet set ";
  sql += body.name1;
  sql += " = '"+ body.newValue1 +"'";
  if( body.name2 != undefined )
  {
    sql += ", ";
    sql += body.name2;
    sql += " = '"+ body.newValue2 +"'";
  }
  if( body.name3 != undefined )
  {
    sql += ", ";
    sql += body.name3;
    sql += " = '"+ body.newValue3 +"'";
  }
  sql += " where union_order='"+ body.unionorder +"'";
  console.log(sql);
  db_util.ExecuteSQL(sql, null,
    (sucData) => 
    {
      console.log(sucData.message);
      res.status(200);
      res.json({"result":"ok", "description":sucData.message});
    },
    (errData) =>
    {
      res.status(200);
      res.json({"result":"error", "errorCode": "1", "description": errData.message});
      console.log(sql);
    }
  );
})

app.post('/QueryBaseMaterial', async (req, res) => {
  try
  {
    var sql = "select * from base_material";
    if( req.body.material_no != undefined )
      sql += " where material_no = '"+ req.body.material_no +"'";
    else if( req.body.keyword != undefined )
      sql += " where material_no like '%"+ req.body.keyword +"%' or name like '%"+ req.body.keyword +"%' or shelf_position like '%"+ req.body.keyword +"%'";
    let ret = await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok","order":ret});
  }
  catch(error)
  {
    console.log('QueryBaseMaterial error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddBaseMaterial', async (req, res) => {
  if( req.body.material_no == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set material_no"});
    return;
  }
  try
  {
    var sql = "select * from base_material where material_no = '"+ req.body.material_no +"'";
    let ret = await db_util.query(sql);
    if( ret.length > 0 )
    {
      var flag = false;
      sql = "update base_material set ";
      if( req.body.name != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "name = '"+ req.body.name +"'";
        flag = true;
      }
      if( req.body.type != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "type = '"+ req.body.type +"'";
        flag = true;
      }
      if( req.body.unit != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "unit = '"+ req.body.unit +"'";
        flag = true;
      }
      if( req.body.safe_stock != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "safe_stock = '"+ req.body.safe_stock +"'";
        flag = true;
      }
      if( req.body.shelf_position != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "shelf_position = '"+ req.body.shelf_position +"'";
        flag = true;
      }
      if( req.body.remark != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "remark = '"+ req.body.remark +"'";
        flag = true;
      }
      if( flag == false )
      {
        res.status(200);
        res.json({"result":"error", "description":"no column was matched to update"});
        console.log('Failed, no column was matched to update base_material');
        return;
      }
      sql += " where material_no = '"+ req.body.material_no +"'";
    }
    else
    {
      var safe_stock = "";
      if( req.body.safe_stock != undefined )
        safe_stock = req.body.safe_stock;
      sql = "insert into base_material values('"+ req.body.material_no +"', '"+ req.body.name +"', '"+ req.body.type +"', '"+ req.body.unit +"', '"+ safe_stock +"', '0', '"+ req.body.shelf_position +"', '"+ req.body.remark +"')";
    }
    console.log(sql);
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('AddBaseMaterial error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateMaterialStock', async (req, res) => {
  if( req.body.material_no == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set material_no"});
    return;
  }
  try
  {
    var sql = "select stock from base_material where material_no = '"+ req.body.material_no +"'";
    let ret = await db_util.query(sql);
    if( ret.length > 0 )
    {
      var count = parseFloat(ret[0].stock);
      if( isNaN(count) )
        count = 0;
      var cnt = parseFloat(req.body.stock);
      if( isNaN(cnt) )
        cnt = 0;
      count += cnt;
      sql = "update base_material set stock = '"+ count +"' where material_no = '"+ req.body.material_no +"'";
      await db_util.query(sql);
      res.status(200);
      res.json({"result":"ok"});
    }
    else
    {
      res.status(200);
      res.json({"result":"error", "description":"not material_no was matched"});
    }
  }
  catch(error)
  {
    console.log('UpdateMaterialStock error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/DeleteBaseMaterial', async (req, res) => {
  if( req.body.material_no == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set material_no"});
    return;
  }
  try
  {
    var sql = "delete from base_material where material_no = '"+ req.body.material_no +"'";
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('DeleteBaseMaterial error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryFirmInfo', async (req, res) => {
  try
  {
    let ret = await db_util.query("select * from firm_info");
    res.status(200);
    res.json({"result":"ok", "order":ret});
  }
  catch(error)
  {
    console.log('QueryFirmInfo error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddFirmInfo', async (req, res) => {
  try
  {
    var sql = "select * from firm_info where fullname = '"+ req.body.fullname +"'";
    let ret = await db_util.query(sql);
    if( ret.length > 0 )
    {
      var flag = false;
      sql = "update firm_info set ";
      if( req.body.shortname != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "shortname = '"+ req.body.shortname +"'";
        flag = true;
      }
      if( req.body.tax_rate != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "tax_rate = '"+ req.body.tax_rate +"'";
        flag = true;
      }
      if( flag == false )
      {
        res.status(200);
        res.json({"result":"error", "description":"no column was matched to update"});
        console.log('Failed, no column was matched to update firm_info');
        return;
      }
      sql += " where fullname = '"+ req.body.fullname +"'";
    }
    else
    {
      if( req.body.shortname != undefined )
        sql = "insert into firm_info values('"+ req.body.fullname +"', '"+ req.body.shortname +"', '"+ req.body.tax_rate +"')";
      else
        sql = "insert into firm_info values('"+ req.body.fullname +"', '', '"+ req.body.tax_rate +"')";
    }
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('AddFirmInfo error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/DeleteFirmInfo', async (req, res) => {
  try
  {
    var sql = "delete from firm_info where fullname = '"+ req.body.fullname +"'";
    let suc = await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('DeleteFirmInfo error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

function dotFixed(str, number) // 字符串，小数点后面的位数
{
  if( str == undefined || str == 'NaN' || str == '' )
    return '0';
  var index = str.indexOf('.');
  if( index < 0 )
    return str;
  var count = 2;
  if( number != undefined )
  {
    count = parseInt(number);
    if( isNaN(count) )
      count = 2;
  }
  if( str.split('.')[1].length <= count )
    return str;
  var temp = parseFloat(str).toFixed(count);
  return temp;
}

app.post('/QueryWarehouse', async (req, res) => {
  try
  {
    var sql = "select * from warehouse";
    if( req.body.material_no != undefined )
      sql += " where material_no = '"+ req.body.material_no +"'";
    else if( req.body.keyword != undefined )
      sql += " where material_no like '%"+ req.body.keyword +"%' OR PR_NO like '%"+ req.body.keyword +"%' OR PO_NO like '%"+ req.body.keyword +"%' OR manufacturer like '%"+ req.body.keyword +"%'";
    let suc = await db_util.query(sql);
    var array = new Array();
    var i = 0;
    var count = 50;
    if( req.body.offset != undefined )
    {
      i = parseInt(req.body.offset);
      if( isNaN(i) )
        i = 0;
    }
    if( req.body.count != undefined )
    {
      count = parseInt(req.body.count);
      if( isNaN(count) )
        count = 50;
    }
    var index = -1;
    suc.forEach(element => {
      index ++;
      if( index >= i )
      {
        if( array.length < count )
        {
          element["quatity"] = dotFixed(element["quatity"]);
          array.push(element);
        }
      }
    });
    res.status(200);
    res.json({"result":"ok","order":array,"total_count":suc.length});
  }
  catch(error)
  {
    console.log('QueryWarehouse error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddWarehouse', async (req, res) => {
  try
  {
    var quatity = 0.0;
    var sql = "select * from warehouse where material_no = '"+ req.body.material_no +"'";
    let ret = await db_util.query(sql);
    if( ret.length > 0 )
    {
      quatity = parseFloat(ret[0].quatity);
      if( isNaN(quatity) )
        quatity = 0.0;
      var flag = false;
      sql = "update warehouse set ";
      if( req.body.PR_NO != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "PR_NO = '"+ req.body.PR_NO +"'";
        flag = true;
      }
      if( req.body.PO_NO != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "PO_NO = '"+ req.body.PO_NO +"'";
        flag = true;
      }
      if( req.body.SN != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "SN = '"+ req.body.SN +"'";
        flag = true;
      }
      if( req.body.quatity != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "quatity = '"+ req.body.quatity +"'";
        flag = true;
        var temp = parseFloat(req.body.quatity);
        if( isNaN(temp) )
          temp = 0.0;
        quatity = temp - quatity;
      }
      if( req.body.price != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "price = '"+ req.body.price +"'";
        flag = true;
      }
      if( req.body.manufacturer != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "manufacturer = '"+ req.body.manufacturer +"'";
        flag = true;
      }
      if( req.body.currency != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "currency = '"+ req.body.currency +"'";
        flag = true;
      }
      if( req.body.check_no != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "check_no = '"+ req.body.check_no +"'";
        flag = true;
      }
      if( req.body.purchasing_reason != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "purchasing_reason = '"+ req.body.purchasing_reason +"'";
        flag = true;
      }
      if( flag == false )
      {
        res.status(200);
        res.json({"result":"error", "description":"no column was matched to update"});
        console.log('Failed, no column was matched to update base_material');
        return;
      }
      sql += " where material_no = '"+ req.body.material_no +"'";
    }
    else
    {
      quatity = parseFloat(req.body.quatity);
      if( isNaN(quatity) )
        quatity = 0.0;
      sql = "insert into warehouse values('"+ req.body.PR_NO +"', '"+ req.body.PO_NO +"', '"+ req.body.SN +"', '"+ req.body.material_no +"', '"+ req.body.quatity +"', '"+ req.body.price +"', '"+ req.body.manufacturer +"', '"+ req.body.currency +"', '"+ req.body.check_no +"', '"+ req.body.purchasing_reason +"')";
    }
    let suc = await db_util.query(sql);
    sql = "select stock from base_material where material_no = '"+ req.body.material_no +"'";
    let succ2 = await db_util.query(sql);
    if( succ2.length > 0 )
    {
      var stock = parseFloat(succ2[0].stock);
      if( isNaN(stock) )
        stock = 0;
      stock += quatity;
      sql = "update base_material set stock = '"+ stock +"' where material_no = '"+ req.body.material_no +"'";
      await db_util.query(sql);
    }
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('AddWarehouse error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/DeleteWarehouse', async (req, res) => {
  if( req.body.id == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not set id"});
    return;
  }
  try
  {
    var quatity = 0.0;
    var usedQuatity = 0.0;
    var material_no = "";
    var sql = "select * from warehouse where id = '"+ req.body.id +"'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":"the id does not exist"});
      return;
    }
    material_no = suc[0].material_no;
    quatity = parseFloat(suc[0].quatity);
    if( isNaN(quatity) )
      quatity = 0;
    usedQuatity = parseFloat(suc[0].usedQuatity);
    if( isNaN(usedQuatity) )
      usedQuatity = 0;
    sql = "delete from warehouse where id = '"+ req.body.id +"'";
    await db_util.query(sql);
    sql = "select stock from base_material where material_no = '"+ material_no +"'";
    let succ2 = await db_util.query(sql);
    if( succ2.length > 0 )
    {
      var stock = parseFloat(succ2[0].stock);
      if( isNaN(stock) )
        stock = 0;
      stock -= (quatity - usedQuatity);
      sql = "update base_material set stock = '"+ stock +"' where material_no = '"+ material_no +"'";
      await db_util.query(sql);
    }
    else
    {
      console.log('Deletewarehouse: the material_no not exist in base_material, ' + material_no);
    }
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('DeleteWarehouse error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryMaterialSend', async (req, res) => {
  try
  {
    var type = 0; // 1/加工件；2/标准件；3/物料申请单
    var status = 0; // 1/备料中；2/已备料；3/缺料
    if( req.body.type != undefined )
    {
      type = parseInt(req.body.type);
      if( isNaN(type) )
        type = 0;
    }
    if( req.body.status != undefined )
    {
      status = parseInt(req.body.status);
      if( isNaN(status) )
        status = 0;
    }
    console.log('QueryMaterialSend status: ' + status + ', type: ' + type + ', cnc: ' + req.body.cnc);
    var i = 0, j = 0, k = 0;
    var array = new Array();
    var sql = "select * from base_material";
    let material = await db_util.query(sql);
    var filter_cnc = false;
    if( req.body.cnc != undefined && req.body.cnc != '' )
      filter_cnc = true;
    sql = "select union_order, delivery_date, charge_department from machining_union_sheet where status = 0 and length(engineer) > 0 and stage != '0000000100'";
    if( req.body.unionorder != undefined )
      sql += " and union_order like '%"+ req.body.unionorder +"%'";
    let suc = await db_util.query(sql);
    for(i=0; i<suc.length; i++)
    {
      sql = "select * from machining_sheet where union_order = '"+ suc[i].union_order +"'";
      if( type == 0 || type == 1 )
      {
        if( req.body.material_no != undefined )
          sql += " and material_no like '%"+ req.body.material_no +"%'";
      }
      let suc2 = await db_util.query(sql);
      if( suc2.length == 0 )
        continue;

      if( type == 0 || type == 1 )
      {
        sql = "select * from dispatch_sheet where union_order = '"+ suc[i].union_order +"'";
        if( status == 1 || status == 2 ) // =3（缺料）时表中的数据状态是1（备料中）
          sql += " and beiliao_ztai = '"+ status +"'";
        sql += " and xlcc_x != '' and xlcc_y != '' and xlcc_z != ''";
        if( filter_cnc )
          sql += " and cnc like '%"+ req.body.cnc +"%'";
        let suc3 = await db_util.query(sql);
        for(j=0; j<suc3.length; j++)
        {
          if( req.body.material_no != undefined )
          {
            for(k=0; k<suc2.length; k++)
            {
              if( suc2[k].sheet_order == suc3[j].ljmc )
              {
                break;
              }
            }
            if( k == suc2.length )
              continue;
          }
          var json = {};
          json["id"] = suc3[j].id;
          json["union_order"] = suc[i].union_order; // 工联单号
          json["delivery_date"] = suc[i].delivery_date; // 治具交期
          json["charge_department"] = suc[i].charge_department;// 付费部门
          json["name"] = "";//suc3[j].ljmc; // 名称
          json["cnc"] = suc3[j].cnc; // 机台
          json["czhi"] = suc3[j].czhi; // 材质
          json["xlcc_x"] = suc3[j].xlcc_x; // 下料尺寸X
          json["xlcc_y"] = suc3[j].xlcc_y; // 下料尺寸Y
          json["xlcc_z"] = suc3[j].xlcc_z; // 下料尺寸Z
          json["xlcc_bs"] = suc3[j].xlcc_bs; // 板数
          json["xlcc_pb"] = suc3[j].xlcc_pb; // 拼板
          json["lingliao_ren"] = suc3[j].lingliao_ren; // 领料人
          json["lingliao_riqi"] = suc3[j].lingliao_riqi; // 领料日期
          json["lingliao_qixian"] = suc3[j].lingliao_qixian; // 领料期限
          json["lingliao_bzhu"] = suc3[j].lingliao_bzhu; // 领料备注
          json["xuhao"] = suc3[j].xuhao; // 序号
          json["type_flag"] = "1"; // 标记：1/加工件；0/标准件
          json["yibei_shuliang"] = suc3[j].yibei_shuliang;
          json["tuiku_shuliang"] = dotFixed(suc3[j].tuiku_shuliang);
          json["beiliao_ztai"] = suc3[j].beiliao_ztai;
          json["material_no"] = ""; // 料号
          for(k=0; k<suc2.length; k++)
          {
            if( suc2[k].sheet_order == suc3[j].ljmc )
            {
              if( json["lingliao_ren"] == '' )
                json["lingliao_ren"] = suc2[k].picking_man;
              json["material_no"] = suc2[k].material_no;
              json["quatity_total"] = dotFixed(suc2[k].quatity_total); // 需求总量
              json["stock"] = '0';
              for(k=0; k<material.length; k++)
              {
                if( material[k].material_no == json["material_no"] )
                {
                  json["name"] = material[k].name;
                  json["unit"] = material[k].unit; // 单位
                  json["position"] = material[k].shelf_position; // 架位
                  json["stock"] = dotFixed(material[k].stock); // 现有库存
                  if( json["stock"] == '0' || json["stock"] == '' )
                    json["beiliao_ztai"] = 3;
                  break;
                }
              }
              if( k == material.length ) // 没找到
              {
                json["name"] = "";
                json["unit"] = "";
                json["position"] = "";
                json["stock"] = '0';
                json["beiliao_ztai"] = 3;
              }
              break;
            }
          }
          if( json["beiliao_ztai"] == 3 )
          {
            if( status == 0 || status == 3 )
              array.push(json);
          }
          else if( status == 0 || json["beiliao_ztai"] == status )
          {
            array.push(json);
          }
        }
      }

      if( filter_cnc )
        continue;
      if( type == 0 || type == 2 )
      {
        // 加标准件
        for(k=0; k<suc2.length; k++)
        {
          if( suc2[k].type_flag != 0 )
            continue;
          //if( status != 0 && status != suc2[k].beiliao_ztai )
          //  continue;

          var json = {};
          json["id"] = parseInt(suc2[k].id) + 500000000;
          json["union_order"] = suc[i].union_order;
          json["delivery_date"] = suc[i].delivery_date;
          json["charge_department"] = suc[i].charge_department;
          json["name"] = suc2[k].sheet_order;
          json["cnc"] = "";
          json["czhi"] = "";
          json["xlcc_x"] = "";
          json["xlcc_y"] = "";
          json["xlcc_z"] = "";
          json["xlcc_bs"] = "";
          json["xlcc_pb"] = "";
          json["lingliao_ren"] = suc2[k].picking_man;
          json["lingliao_riqi"] = suc2[k].lingliao_riqi;
          json["lingliao_qixian"] = suc2[k].lingliao_qixian;
          json["lingliao_bzhu"] = suc2[k].lingliao_bzhu;
          json["xuhao"] = suc2[k].xuhao;
          json["type_flag"] = "0";
          json["material_no"] = suc2[k].material_no;
          json["quatity_total"] = dotFixed(suc2[k].quatity_total);
          json["yibei_shuliang"] = suc2[k].yibei_shuliang;
          json["tuiku_shuliang"] = dotFixed(suc2[k].tuiku_shuliang);
          json["beiliao_ztai"] = suc2[k].beiliao_ztai;
          json["stock"] = '0';
          for(j=0; j<material.length; j++)
          {
            if( material[j].material_no == json["material_no"] )
            {
              json["name"] = material[j].name;
              json["unit"] = material[j].unit;
              json["position"] = material[j].shelf_position;
              json["stock"] = dotFixed(material[j].stock);
              if( json["stock"] == '0' || json["stock"] == '' )
                json["beiliao_ztai"] = 3;
              break;
            }
          }
          if( j == material.length ) // 没找到
          {
            json["name"] = "";
            json["unit"] = "";
            json["position"] = "";
            json["stock"] = '0';
            json["beiliao_ztai"] = 3;
          }
          if( json["beiliao_ztai"] == 3 )
          {
            if( status == 0 || status == 3 )
              array.push(json);
          }
          else if( status == 0 || json["beiliao_ztai"] == status )
          {
            array.push(json);
          }
        }
      }
    }

    if( (type == 0 || type == 3) && filter_cnc == false )
    {
      sql = "select * from material_apply where checker != ''"; // 签核后才显示
      if( status == 1 || status == 2 ) // =3（缺料）时表中的数据状态是1（备料中）
        sql += " and beiliao_ztai = '"+ status +"'";
      if( req.body.material_no != undefined )
        sql += " and material_no like '%"+ req.body.material_no +"%'";
      let suc4 = await db_util.query(sql);
      for(i=0; i<suc4.length; i++)
      {
        if( suc4[i].lingliao_riqi != '' )
          continue;
        var json = {};
        json["id"] = parseInt(suc4[i].id) + 2000000000;
        json["union_order"] = suc4[i].applyID;
        json["delivery_date"] = "";
        json["charge_department"] = suc4[i].charge_department;
        json["name"] = suc4[i].name;
        json["cnc"] = "";
        json["czhi"] = "";
        json["xlcc_x"] = "";
        json["xlcc_y"] = "";
        json["xlcc_z"] = "";
        json["xlcc_bs"] = "";
        json["xlcc_pb"] = "";
        json["lingliao_ren"] = suc4[i].applicant;
        json["lingliao_riqi"] = "";
        json["lingliao_qixian"] = "";
        json["lingliao_bzhu"] = suc4[i].remark;
        json["xuhao"] = "";
        json["type_flag"] = "2";
        json["material_no"] = suc4[i].material_no;
        json["quatity_total"] = dotFixed(suc4[i].quatity);
        json["yibei_shuliang"] = suc4[i].yibei_shuliang;
        json["tuiku_shuliang"] = dotFixed(suc4[i].tuiku_shuliang);
        json["beiliao_ztai"] = suc4[i].beiliao_ztai;
        json["stock"] = '0';
        for(j=0; j<material.length; j++)
        {
          if( material[j].material_no == json["material_no"] )
          {
            json["name"] = material[j].name;
            json["unit"] = material[j].unit;
            json["position"] = material[j].shelf_position;
            json["stock"] = dotFixed(material[j].stock);
            if( json["stock"] == '0' || json["stock"] == '' )
              json["beiliao_ztai"] = 3;
            break;
          }
        }
        if( j == material.length ) // 没找到
        {
          json["name"] = "";
          json["unit"] = "";
          json["position"] = "";
          json["stock"] = '0';
          json["beiliao_ztai"] = 3;
        }
        if( json["beiliao_ztai"] == 3 )
        {
          if( status == 0 || status == 3 )
            array.push(json);
        }
        else if( status == 0 || json["beiliao_ztai"] == status )
        {
          array.push(json);
        }
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueyrMaterialSend error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryOrderStatus', async (req, res) => {
  try
  {
    var sql = "select id, beiliao_ztai from machining_sheet where union_order = '"+ req.body.unionorder +"' and type_flag = 0";
    let suc = await db_util.query(sql);
    var flag = "True";
    for(var i=0; i<suc.length; i++)
    {
      if( suc[i].beiliao_ztai != 2 )
      {
        flag = "False";
        break;
      }
    }
    res.status(200);
    res.json({"result":"ok","order":flag});
  }
  catch(error)
  {
    console.log('QueyrOrderStatus error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateMaterialSend', async (req, res) => {
  var sql = "";
  try
  {
    var body = req.body;
    var id = 0;
    var where = "";
    if( body.id == undefined )
    {
      if( body.unionorder == undefined )
      {
        res.status(200);
        res.json({"result":"error", "description":"the id or unionorder is not found"});
        return;
      }
      where = " where union_order = '"+ body.unionorder +"'";
    }
    else
    {
      id = parseInt(body.id); // 大于5亿：大表machining_sheet；大于20亿：物料申请表
      if( isNaN(id) )
        id = 0;
      var temp = id;
      if( id > 2000000000 )
        temp -= 2000000000;
      else if( id > 500000000 )
        temp -= 500000000;
      where = " where id = '"+ temp +"'";
    }
    var flag = false;
    if( id > 2000000000 )
    {
      sql = "update material_apply set ";
      if( body.lingliao_ren != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "applicant = '"+ body.lingliao_ren +"'";
        flag = true;
      }
    }
    else if( id > 500000000 )
    {
      sql = "update machining_sheet set ";
      if( body.lingliao_ren != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "picking_man = '"+ body.lingliao_ren +"'";
        flag = true;
      }
    }
    else if( id > 0 )
    {
      sql = "update dispatch_sheet set ";
      if( body.lingliao_ren != undefined )
      {
        if( flag )
          sql += ", ";
        sql += "lingliao_ren = '"+ body.lingliao_ren +"'";
        flag = true;
      }
    }
    else // 传的是工联单号，修改所有标准件的领料时间
    {
      sql = "update machining_sheet set ";
      where = " where union_order = '"+ body.unionorder +"' and type_flag = 0";
    }
    if( body.lingliao_riqi != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "lingliao_riqi = '"+ body.lingliao_riqi +"'";
      flag = true;
    }
    if( body.lingliao_qixian != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "lingliao_qixian = '"+ body.lingliao_qixian +"'";
      flag = true;
    }
    if( body.lingliao_bzhu != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "lingliao_bzhu = '"+ body.lingliao_bzhu +"'";
      flag = true;
    }
    if( body.xuhao != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "xuhao = '"+ body.xuhao +"'";
      flag = true;
    }
    if( body.yibei_shuliang != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "yibei_shuliang = '"+ body.yibei_shuliang +"'";
      flag = true;
    }
    if( body.tuiku_shuliang != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "tuiku_shuliang = '"+ body.tuiku_shuliang +"'";
      flag = true;
    }
    if( body.beiliao_ztai != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "beiliao_ztai = '"+ body.beiliao_ztai +"'";
      flag = true;
    }
    if( flag )
    {
      sql += where;
      let sucData = await db_util.query(sql);
      console.log(sql);
      var json = {};
      json["result"] = "ok";
      if( sucData.affectedRows > 0)
        json["description"] = "changedRows";
      else
        json["description"] = "not find the record";
      if( body.lingliao_riqi != undefined )
      {
        if( id > 2000000000 ) // 物料申请表中如果这个栏位有值就不再显示了
        {
          sql = "update material_apply set lingliao_riqi = '"+ body.lingliao_riqi +"' where id = '"+ id +"'";
          await db_util.query(sql);
        }
      }
      if( body.stock != undefined )
      {
        var material_no = "";
        var union_order = "";
        var sheet_order = "";
        if( id > 2000000000 )
        {
          id -= 2000000000;
          sql = "update material_apply set stock = '"+ body.stock +"' where id = '"+ id +"'";
          await db_util.query(sql);
          console.log(sql);
          sql = "select applyID, material_no, applyType from material_apply where id = '"+ id +"'";
          let suc = await db_util.query(sql);
          if( suc.length > 0 )
          {
            union_order = suc[0].applyID;
            material_no = suc[0].material_no;
            sheet_order = suc[0].applyType;
          }
        }
        else if( id > 500000000 )
        {
          id -= 500000000;
          sql = "select union_order, sheet_order, material_no from machining_sheet where id = '"+ id +"'";
          let suc = await db_util.query(sql);
          if( suc.length > 0 )
          {
            union_order = suc[0].union_order;
            material_no = suc[0].material_no;
            sheet_order = suc[0].sheet_order;
          }
        }
        else
        {
          sql = "select union_order, ljmc from dispatch_sheet where id = '"+ id +"'"
          let suc = await db_util.query(sql);
          if( suc.length > 0 )
          {
            union_order = suc[0].union_order;
            sheet_order = suc[0].ljmc;
            sql = "select material_no from machining_sheet where union_order = '"+ union_order +"' and sheet_order = '"+ sheet_order +"'";
            let suc2 = await db_util.query(sql);
            if( suc2.length > 0 )
              material_no = suc2[0].material_no;
          }
        }
        sql = "select stock from base_material where material_no = '"+ material_no +"'";
        let suc = await db_util.query(sql);
        do
        {
          if( suc.length == 0 )
            break;
          var stock = parseFloat(suc[0].stock); // 原来的库存
          if( isNaN(stock) )
            stock = 0;
          /*if( stock <= 0 )
          {
            console.log('库房中料号' + material_no + '库存为0');
            break;
          }*/
          var stockTemp = parseFloat(body.stock); // 传入的是更新后的库存
          if( isNaN(stockTemp) )
            stockTemp = 0;
          /*if( stockTemp <= 0 )
            break;
          if( stock < stockTemp )
          {
            console.log('库房中料号' + material_no + '库存为' + stock + '，不足以发放：' + stockTemp);
          }*/
          stock -= stockTemp; // stock如果小于0表示退库
          if( stock == 0 )
            break;
          sql = "update base_material set stock = '"+ body.stock +"' where material_no = '"+ material_no +"'";
          await db_util.query(sql);
          console.log(sql);
          
          var date = new Date();
          var timestamp = getMonthDayTime(date, 1, 1);
          sql = "select id, quatity, price, manufacturer, usedQuatity from warehouse where material_no = '"+ material_no +"'";
          let suc3 = await db_util.query(sql);
          if( stock > 0 )
          {
            for(var i=0; i<suc3.length; i++)
            {
              var quatity = parseFloat(suc3[i].quatity);
              if( isNaN(quatity) )
                continue;
              var usedQuatity = parseFloat(suc3[i].usedQuatity);
              if( isNaN(usedQuatity) )
                usedQuatity = 0;
              if( usedQuatity >= quatity )
                continue;
              var price = await GetPriceAfterTax(suc3[i].price, suc3[i].manufacturer);
              if( (quatity - usedQuatity) >= stock )
              {
                sql = "insert into material_send values (null, '"+ union_order +"', '"+ sheet_order +"', '"+ material_no +"', '"+ stock +"', '"+ price +"', '"+ suc3[i].id +"', '"+ timestamp +"')";
                await db_util.query(sql);
                console.log(sql);
                usedQuatity += stock;
                sql = "update warehouse set usedQuatity = '"+ usedQuatity +"' where id = '"+ suc3[i].id +"'";
                await db_util.query(sql);
                console.log(sql);
                break;
              }
              else
              {
                var temp = quatity - usedQuatity;
                sql = "insert into material_send values (null, '"+ union_order +"', '"+ sheet_order +"', '"+ material_no +"', '"+ temp +"', '"+ price +"', '"+ suc3[i].id +"', '"+ timestamp +"')";
                await db_util.query(sql);
                console.log(sql);
                stock -= temp;
                sql = "update warehouse set usedQuatity = '"+ quatity +"' where id = '"+ suc3[i].id +"'";
                await db_util.query(sql);
                console.log(sql);
              }
            }
          }
          else // 退库
          {
            stockTemp = 0 - stock;
            for(var i=suc3.length-1; i>=0; i--)
            {
              var quatity = parseFloat(suc3[i].quatity);
              if( isNaN(quatity) )
                continue;
              var usedQuatity = parseFloat(suc3[i].usedQuatity);
              if( isNaN(usedQuatity) )
                usedQuatity = 0;
              if( usedQuatity <= 0 )
                continue;
              if( stockTemp < usedQuatity )
              {
                sql = "update warehouse set usedQuatity = '"+ (usedQuatity - stockTemp) +"' where id = '"+ suc3[i].id +"'";
                stockTemp = 0;
              }
              else
              {
                sql = "update warehouse set usedQuatity = '0' where id = '"+ suc3[i].id +"'";
                stockTemp -= usedQuatity;
              }
              await db_util.query(sql);
              console.log(sql);
              if( stockTemp <= 0 )
                break;
            }
            if( stockTemp > 0 )
            {
              console.log('还有' + stockTemp + '件没有退库******');
            }
          }
        }while(false);
      }
      res.status(200);
      res.json(json);
    }
    else
    {
      res.status(200);
      res.json({"result":"error", "description":"no column was matched to update"});
      console.log('Failed: ' + sql);
    }
  }
  catch(error)
  {
    console.log('UpdateMaterialSend error: ' + error.message + ', SQL: ' + sql);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryMaterialSendEx', async (req, res) => {
  try
  {
    var sql = "";
    var beiliao_ztai = 0;
    var i = 0, j = 0, k = 0;
    var array = new Array();
    var union_order = "";
    if( req.body.unionorder != undefined )
      union_order = req.body.unionorder;
    if( req.body.beiliao_ztai != undefined )
    {
      beiliao_ztai = parseInt(req.body.beiliao_ztai);
      if( isNaN(beiliao_ztai) )
        beiliao_ztai = 0;
    }
    console.log('QueryMaterialSendEx ' + union_order + ' ' + beiliao_ztai);
    if( union_order.length == 0 )
    {
      sql = "select union_order, name, quatity, delivery_date, charge_department, total_time from machining_union_sheet where status = 0 and length(engineer) > 0";
      let suc = await db_util.query(sql);
      for(i=0; i<suc.length; i++)
      {
        j = 0;
        var queliao = 0;
        var yibeiliao = 0;
        var beiliaozhong = 0;
        // 所有工件都领料之后就不显示
        sql = "select * from machining_sheet where union_order = '"+ suc[i].union_order +"' and type_flag = 0";
        let suc2 = await db_util.query(sql);
        for(k=0; k<suc2.length; k++)
        {
          if( suc2[k].beiliao_ztai == 3 )
            queliao ++;
          else if( suc2[k].beiliao_ztai == 1 )
            beiliaozhong ++;
          else if( suc2[k].beiliao_ztai == 2 )
          {
            yibeiliao ++;
            if( suc2[k].lingliao_riqi == '' ) // 已备料但没有领料
              j ++;
          }
        }
        sql = "select * from dispatch_sheet where union_order = '"+ suc[i].union_order +"'";
        let suc3 = await db_util.query(sql);
        for(k=0; k<suc3.length; k++)
        {
          if( suc3[k].beiliao_ztai == 3 )
            queliao ++;
          else if( suc3[k].beiliao_ztai == 1 )
            beiliaozhong ++;
          else if( suc3[k].beiliao_ztai == 2 )
          {
            yibeiliao ++;
            if( suc3[k].lingliao_riqi == '' )
              j ++;
          }
        }
        if( j == 0 && yibeiliao == (suc2.length + suc3.length) ) // 都已领料
          continue;
        if( queliao > 0 )
          j = 3;
        else if( yibeiliao == (suc2.length + suc3.length) )
          j = 2;
        else
          j = 1;
        if( beiliao_ztai != 0 && beiliao_ztai != j )
          continue;
        var json = {};
        json["type_flag"] = 0;
        json["union_order"] = suc[i].union_order; // 工联单号
        json["delivery_date"] = suc[i].delivery_date; // 治具交期
        json["charge_department"] = suc[i].charge_department;// 付费部门
        json["name"] = suc[i].name; // 名称
        json["quatity"] = suc[i].quatity;
        json["total_time"] = suc[i].total_time;
        json["beiliao_ztai"] = j;
        array.push(json);
      }
      sql = "select * from material_apply";
      let suc4 = await db_util.query(sql);
      for(i=0; i<suc4.length; i++)
      {
        if( suc4[i].beiliao_ztai == 2 && suc4[i].lingliao_riqi.length != '' )
          continue;
        if( beiliao_ztai != 0 && beiliao_ztai != suc4[i].beiliao_ztai )
          continue;
        var json = {};
        json["type_flag"] = 3;
        json["union_order"] = suc4[i].applyID;
        json["delivery_date"] = "";
        json["charge_department"] = suc4[i].charge_department;
        json["name"] = suc4[i].name;
        json["quatity"] = suc4[i].quatity;
        json["total_time"] = "";
        json["beiliao_ztai"] = suc4[i].beiliao_ztai;
        array.push(json);
      }
      res.status(200);
      res.json({"result":"ok", "order":array});
      return;
    }
    //sql = "select * from base_material";
    //let material = await db_util.query(sql);
    sql = "select * from machining_union_sheet where union_order = '"+ union_order +"'";
    let suc = await db_util.query(sql);
    sql = "select * from machining_sheet where union_order = '"+ union_order +"'";
    let suc2 = await db_util.query(sql);
    sql = "select * from dispatch_sheet where union_order = '"+ union_order +"'";
    let suc3 = await db_util.query(sql);
    i = 0;
    for(j=0; j<suc3.length; j++)
    {
      if( beiliao_ztai != 0 && beiliao_ztai != suc3[j].beiliao_ztai )
          continue;
      var json = {};
      json["type_flag"] = 1;
      json["union_order"] = union_order; // 工联单号
      json["delivery_date"] = suc[i].delivery_date; // 治具交期
      json["charge_department"] = suc[i].charge_department;// 付费部门
      json["name"] = suc3[j].ljmc; // 名称
      json["quatity"] = suc3[j].gjsl;
      json["total_time"] = suc3[j].gzsj_tongji;
      json["beiliao_ztai"] = suc3[j].beiliao_ztai;
      for(k=0; k<suc2.length; k++)
      {
        if( suc2[k].sheet_order == json["name"] )
        {
          json["quatity"] = suc2[k].quatity_total; // 需求总量
          break;
        }
      }
      json["lingliao_riqi"] = suc3[j].lingliao_riqi;
      json["lingliao_qixian"] = suc3[j].lingliao_qixian;
      array.push(json);
    }
    // 加标准件
    for(k=0; k<suc2.length; k++)
    {
      if( suc2[k].type_flag != '0' )
        continue;
      if( beiliao_ztai != 0 && beiliao_ztai != suc2[k].beiliao_ztai )
        continue;
      var json = {};
      json["type_flag"] = 0;
      json["union_order"] = suc[i].union_order;
      json["delivery_date"] = suc[i].delivery_date;
      json["charge_department"] = suc[i].charge_department;
      json["name"] = suc2[k].sheet_order;
      json["quatity"] = suc2[k].quatity_total;
      json["total_time"] = suc2[k].speed_time;
      json["beiliao_ztai"] = suc2[k].beiliao_ztai;
      json["lingliao_riqi"] = suc2[k].lingliao_riqi;
      json["lingliao_qixian"] = suc2[k].lingliao_qixian;
      array.push(json);
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueyrMaterialSendEx error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryMaterialApply', async (req, res) => {
  try
  {
    var sql = "select * from material_apply";
    if( req.body.material_no != undefined )
      sql += " where material_no = '"+ req.body.material_no +"'";
    else
      sql += " where lingliao_riqi = ''";
    let ret = await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok","order":ret});
  }
  catch(error)
  {
    console.log('QueryMaterialApply error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddMaterialApply', async (req, res) => {
  try
  {
    var body = req.body;
    var date = new Date();
    var day = "" + date.getFullYear();
    if( date.getMonth() < 9 )
      day += '0';
    day += (date.getMonth() + 1);
    if( date.getDate() < 10 )
      day += '0';
    day += date.getDate();
    var days = day + "%";
    var sql = "select applyID from material_apply where applyID like '"+ days +"' order by applyID desc limit 1";
    let ret = await db_util.query(sql);
    if( ret.length > 0 )
    {
      var id = parseInt(ret[0].applyID.substr(8));
      if( isNaN(id) )
        id = 0;
      id ++;
      if( id < 10 )
        day += '000';
      else if( id < 100 )
        day += '00';
      else if( id < 1000 )
        day += '0';
      day += id;
    }
    else
    {
      day += '0001';
    }
    sql = "insert into material_apply values(null, '"+ day +"', '"+ body.material_no +"', '"+ body.name +"', '"+ body.unit +"', '"+ body.stock +"', '"+ body.applyType +"', '"+ body.charge_department +"', '"+ body.applicant +"', '"+ body.quatity +"', '', '"+ body.remark +"', '', '', 1, '')";
    await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok","ID":day});
  }
  catch(error)
  {
    console.log('AddMaterialApply error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateMaterialApply', async (req, res) => {
  try
  {
    var body = req.body;
    if( body.id == undefined )
    {
      res.status(200);
      res.json({"result":"error", "description":"not set id"});
      return;
    }
    var flag = false;
    var sql = "Update material_apply set ";
    if( body.applyID != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "applyID = '"+ body.applyID +"'";
      flag = true;
    }
    if( body.material_no != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "material_no = '"+ body.material_no +"'";
      flag = true;
    }
    if( body.name != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "name = '"+ body.name +"'";
      flag = true;
    }
    if( body.unit != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "unit = '"+ body.unit +"'";
      flag = true;
    }
    if( body.stock != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "stock = '"+ body.stock +"'";
      flag = true;
    }
    if( body.applyType != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "applyType = '"+ body.applyType +"'";
      flag = true;
    }
    if( body.charge_department != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "charge_department = '"+ body.charge_department +"'";
      flag = true;
    }
    if( body.applicant != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "applicant = '"+ body.applicant +"'";
      flag = true;
    }
    if( body.quatity != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "quatity = '"+ body.quatity +"'";
      flag = true;
    }
    if( body.checker != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "checker = '"+ body.checker +"'";
      flag = true;
    }
    if( body.remark != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "remark = '"+ body.remark +"'";
      flag = true;
    }
    if( body.yibei_shuliang != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "yibei_shuliang = '"+ body.yibei_shuliang +"'";
      flag = true;
    }
    if( body.tuiku_shuliang != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "tuiku_shuliang = '"+ body.tuiku_shuliang +"'";
      flag = true;
    }
    if( body.beiliao_ztai != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "beiliao_ztai = '"+ body.beiliao_ztai +"'";
      flag = true;
    }
    if( flag )
    {
      sql += " where id = '"+ body.id +"'";
      let sucData = await db_util.query(sql);
      var json = {};
      json["result"] = "ok";
      if( sucData.affectedRows > 0)
        json["description"] = "changedRows";
      else
        json["description"] = "not find the record";
      res.status(200);
      res.json(json);
    }
    else
    {
      res.status(200);
      res.json({"result":"error", "description":"no column was matched to update"});
      console.log('Failed: ' + sql);
    }
  }
  catch(error)
  {
    console.log('UpdateMaterialApply error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateWarehouse', async (req, res) => {
  try
  {
    var body = req.body;
    if( body.id == undefined )
    {
      res.status(200);
      res.json({"result":"error", "description":"not set id"});
      return;
    }
    var flag = false;
    var sql = "select material_no, quatity from warehouse where id = '"+ body.id +"'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":"the id does not exist"});
      return;
      
    }
    sql = "Update warehouse set ";
    if( body.PR_NO != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "PR_NO = '"+ body.PR_NO +"'";
      flag = true;
    }
    if( body.PO_NO != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "PO_NO = '"+ body.PO_NO +"'";
      flag = true;
    }
    if( body.SN != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "SN = '"+ body.SN +"'";
      flag = true;
    }
    if( body.material_no != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "material_no = '"+ body.material_no +"'";
      flag = true;
    }
    if( body.quatity != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "quatity = '"+ body.quatity +"'";
      flag = true;
    }
    if( body.price != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "price = '"+ body.price +"'";
      flag = true;
    }
    if( body.manufacturer != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "manufacturer = '"+ body.manufacturer +"'";
      flag = true;
    }
    if( body.currency != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "currency = '"+ body.currency +"'";
      flag = true;
    }
    if( body.check_no != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "check_no = '"+ body.check_no +"'";
      flag = true;
    }
    if( body.reason != undefined )
    {
      if( flag )
        sql += ", ";
      sql += "purchasing_reason = '"+ body.purchasing_reason +"'";
      flag = true;
    }
    if( flag )
    {
      sql += " where id = '"+ body.id +"'";
      let sucData = await db_util.query(sql);
      var json = {};
      json["result"] = "ok";
      if( sucData.affectedRows > 0)
        json["description"] = "changedRows";
      else
        json["description"] = "not find the record";
      if( body.material_no != undefined && body.material_no != suc[0].material_no )
      {
        // 旧料号的库存需要减掉
        sql = "select stock from base_material where material_no = '"+ suc[0].material_no +"'";
        let suc2 = await db_util.query(sql);
        if( suc2.length > 0 )
        {
          var stock = parseFloat(suc2[0].stock) - parseFloat(suc[0].quatity);
          sql = "update base_material set stock = '"+ stock +"' where material_no = '"+ suc[0].material_no +"'";
          await db_util.query(sql);
        }
        // 新料号的库存需要增加
        sql = "select stock from base_material where material_no = '"+ body.material_no +"'";
        let suc3 = await db_util.query(sql);
        if( suc3.length > 0 )
        {
          var stock = parseFloat(suc3[0].stock);
          if( body.quatity != undefined )
            stock += parseFloat(body.quatity);
          else
            stock += parseFloat(suc[0].quatity);
          sql = "update base_material set stock = '"+ stock +"' where material_no = '"+ body.material_no +"'";
          await db_util.query(sql);
        }
      }
      else if( body.quatity != undefined && body.quatity != suc[0].quatity )
      {
        sql = "select stock from base_material where material_no = '"+ suc[0].material_no +"'";
        let suc4 = await db_util.query(sql);
        if( suc4.length > 0 )
        {
          var stock = parseFloat(suc4[0].stock) - parseFloat(suc[0].quatity) + parseFloat(body.quatity);
          sql = "update base_material set stock = '"+ stock +"' where material_no = '"+ suc[0].material_no +"'";
          await db_util.query(sql);
        }
      }
      res.status(200);
      res.json(json);
    }
    else
    {
      res.status(200);
      res.json({"result":"error", "description":"no column was matched to update"});
      console.log('Failed: ' + sql);
    }
  }
  catch(error)
  {
    console.log('UpdateWarehouse error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddDownloadCount', async (req, res) => {
  try
  {
    var sql = "";
    var download_count = 1;
    let ret = await db_util.query("select * from cncother where name = 'downloadcount'");
    if( ret.length > 0 )
    {
      var count = parseInt(ret[0].value);
      if( isNaN(count) )
        count = 0;
      download_count += count;
    }
    if( ret.length == 0 )
      sql = "insert into cncother (name, value) values('downloadcount', '"+ download_count +"')";
    else
      sql = "update cncother set value = '"+ download_count +"' where name = 'downloadcount'";
    await db_util.query(sql);
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('AddDownloadCount error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})
// 总检报表
app.post('/QueryBaobiaoZongjian', async (req, res) => {
  try
  {
    var sql = "select id, union_order, songjian_time, zongjian_ok_count, zongjian_ng_count from machining_union_sheet where songjian_time != ''";
    var starttime = 0;
    var endtime = Date.now();
    if( req.body.starttime != undefined )
      starttime = Date.parse(req.body.starttime);
    if( req.body.endtime != undefined )
      endtime = Date.parse(req.body.endtime);
    let suc = await db_util.query(sql);
    var array = new Array();
    var i, k, songjian_time = 0, count = 0;
    var riqi = "";
    var date = new Date();
    for(i=0; i<suc.length; i++)
    {
      songjian_time = Date.parse(suc[i].songjian_time);
      if( songjian_time < starttime || songjian_time >= endtime )
        continue;
      date.setTime(songjian_time);
      riqi = getMonthDayTime(date, 1);
      for(k=0; k<array.length; k++)
      {
        if( array[k]["day"] == riqi )
        {
          count = parseInt(suc[i].zongjian_ng_count);
          if( isNaN(count) )
            count = 0;
          array[k]["ng"] += count;
          count = parseInt(suc[i].zongjian_ok_count);
          if( isNaN(count) )
            count = 0;
          array[k]["ok"] += count;
          break;
        }
      }
      if( k >= array.length )
      {
        var json = {};
        json["day"] = riqi;
        count = parseInt(suc[i].zongjian_ng_count);
        if( isNaN(count) )
          count = 0;
        json["ng"] = count;
        count = parseInt(suc[i].zongjian_ok_count);
        if( isNaN(count) )
          count = 0;
        json["ok"] = count;
        array.push(json);
      }
    }
    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoZongjian error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})
// 品检报表
app.post('/QueryBaobiaoPinjian', async (req, res) => {
  try
  {
    var sql = "select id, songjian_shijian, gjjcjg from dispatch_sheet where songjian_shijian != ''";
    var starttime = 0;
    var endtime = Date.now();
    if( req.body.starttime != undefined )
      starttime = Date.parse(req.body.starttime);
    if( req.body.endtime != undefined )
      endtime = Date.parse(req.body.endtime);
    let suc = await db_util.query(sql);
    var array = new Array();
    var i, j, k, index, songjian_shijian = 0;
    var riqi = "";
    var date = new Date();
    for(i=0; i<suc.length; i++)
    {
      songjian_shijian = Date.parse(suc[i].songjian_shijian);
      if( songjian_shijian < starttime || songjian_shijian >= endtime )
        continue;
      index = suc[i].gjjcjg.indexOf(',');
      if( index < 1 )
        continue;
      riqi = suc[i].gjjcjg.slice(0, index); // NG
      j = parseInt(riqi);
      riqi = suc[i].gjjcjg.slice(index+1); // OK
      k = parseInt(riqi);
      date.setTime(songjian_shijian);
      riqi = getMonthDayTime(date, 1);
      for(index=0; index<array.length; index++)
      {
        if( array[index]["day"] == riqi )
        {
          array[index]["ng"] += j;
          array[index]["ok"] += k;
          break;
        }
      }
      if( index >= array.length )
      {
        var json = {};
        json["day"] = riqi;
        json["ng"] = j;
        json["ok"] = k;
        array.push(json);
      }
    }
    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoPinjian error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

async function GetPriceAfterTax(price, manufacturer)
{
  var priceAfterTax = price;
  var sql = "select * from firm_info where fullname = '"+ manufacturer +"'";
  let suc = await db_util.query(sql);
  if( suc.length == 0 )
    return priceAfterTax;
  var rate = parseFloat(suc[0].tax_rate);
  if( isNaN(rate) )
    rate = 0;
  priceAfterTax /= (1 + rate);
  sql = priceAfterTax.toString();
  if( sql.indexOf('.') > 0 && sql.split('.')[1].length > 3 )
    priceAfterTax = priceAfterTax.toFixed(3);
  return priceAfterTax;
}

// 人工工时比例报表
app.post('/QueryBaobiaoGongshi', async (req, res) => {
  try
  {
    var sql = "select * from delivery_sheet where starttime != '' GROUP BY union_order ORDER BY starttime ASC";
    var starttime = 0;
    var endtime = Date.now();
    if( req.body.starttime != undefined )
      starttime = Date.parse(req.body.starttime);
    if( req.body.endtime != undefined )
      endtime = Date.parse(req.body.endtime);
    let succ2 = await db_util.query(sql);
    var array = new Array();
    var i, j, k, lingqu_time = 0;
    var quatity, price;
    var date = new Date();
    for(j=0; j<succ2.length; j++)
    {
      lingqu_time = Date.parse(succ2[j].starttime);
      if( isNaN(lingqu_time) )
        continue;
      if( lingqu_time < starttime || lingqu_time >= endtime )
        continue;
      date.setTime(lingqu_time);
      sql = "select * from machining_union_sheet where union_order = '"+ succ2[j].union_order +"'";
      let suc = await db_util.query(sql);
      if( suc.length == 0 )
        continue;
      i = 0;
      var json = {};
      json["date"] = getMonthDayTime(date, 1);
      json["union_order"] = suc[i].union_order;
      json["name"] = suc[i].name;
      json["quatity"] = parseFloat(suc[i].quatity);
      json["apply_person"] = suc[i].apply_person;
      if( suc[i].factory == undefined )
        json["factory"] = "";
      else
        json["factory"] = suc[i].factory;
      json["charge_department"] = suc[i].charge_department;
      json["total_time"] = suc[i].total_time;
      json["cost"] = 0.0; // 材料费用
      sql = "select id, quatity, price from material_send where union_order = '"+ suc[i].union_order +"'";
      let suc2 = await db_util.query(sql);
      for(k=0; k<suc2.length; k++)
      {
        quatity = parseFloat(suc2[k].quatity);
        if( isNaN(quatity) )
          quatity = 0;
        if( quatity <= 0 )
          continue;
        price = parseFloat(suc2[k].price);
        if( isNaN(price) )
          price = 0.0;
        json["cost"] += quatity * price;
      }
      json["price"] = suc[i].price;
      price = parseFloat(suc[i].price);
      if( isNaN(price) )
        price = 0.0;
      quatity = parseFloat(suc[i].quatity);
      if( isNaN(quatity) )
        quatity = 0.0;
      json["total_price"] = quatity * price;
      array.push(json);
    }
    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoGongshi error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})
// Delay原因分析报表
function parseDelayRemark(time, remark, array)
{
  if( remark == null || time == null )
    return 0;
  if( remark.length == 0 || time.length == 0 )
    return 0;
  var date = new Date(time);
  var month = getMonthDayTime(date);
  var month_name = ['JAN.', 'FEB.', 'MAR.', 'APR.', 'MAY.', 'JUN.', 'JUL.', 'AUG.', 'SEP.', 'OCT.', 'NOV.', 'DEC.'];
  var arr = new Array();
  var index = remark.indexOf(',');
  if( index < 0 )
  {
    arr.push(remark);
  }
  else
  {
    var temp = "";
    var offset = 0;
    while( index >= offset )
    {
      if( index > offset )
      {
        temp = remark.slice(offset, index);
        arr.push(temp);
      }
      offset = index + 1;
      index = remark.indexOf(',', offset);
      if( index < 0 )
      {
        temp = remark.slice(offset);
        if( temp.length > 0 )
          arr.push(temp);
        break;
      }
    }
  }
  var flag = true;
  var j = 0, k = 0, i = 0;
  for(k=0; k<arr.length; k++)
  {
    for(j=0; j<array.length; j++)
    {
      if( array[j].month == month )
      {
        for(i=0; i<array[j]["data"].length; i++)
        {
          if( array[j]["data"][i].name == arr[k] )
          {
            array[j]["data"][i].count ++;
            flag = false;
            break;
          }
        }
      }
    }
    if( flag )
    {
      for(j=0; j<array.length; j++)
      {
        if( array[j].month == month )
        {
          for(i=0; i<array[j]["data"].length; i++)
          {
            if( array[j]["data"][i].name == arr[k] )
            {
              array[j]["data"][i].count ++;
              flag = false;
              break;
            }
          }
          if( flag )
          {
            var json2 = {};
            json2["name"] = arr[k];
            json2["count"] = 1;
            json2["ratio"] = "";
            array[j]["data"].push(json2);
          }
          break;
        }
      }
      if( j == array.length )
      {
        var json = {};
        json["month"] = month;
        json["month_name"] = month_name[date.getMonth()];
        json["data"] = new Array();
        var json2 = {};
        json2["name"] = arr[k];
        json2["count"] = 1;
        json2["ratio"] = "";
        json["data"].push(json2);
        array.push(json);
      }
    }
  }
  return k;
}
app.post('/QueryBaobiaoDelay', async (req, res) => {
  try
  {
    var sql = "select * from machining_union_sheet where status != 2";
    var starttime = 0;
    var endtime = Date.now();
    if( req.body.starttime != undefined )
      starttime = Date.parse(req.body.starttime);
    if( req.body.endtime != undefined )
      endtime = Date.parse(req.body.endtime);
    let suc = await db_util.query(sql);
    var array = new Array();
    var list = new Array();
    var i, k, time = 0;
    var date = new Date();
    for(i=0; i<suc.length; i++)
    {
      time = Date.parse(suc[i].ruku_time);
      if( isNaN(time) )
        time = 0;
      if( time < starttime || time >= endtime )
        continue;
      date.setTime(time);
      time = 0;
      time += parseDelayRemark(suc[i].design_end_date, suc[i].design_remark, array);
      time += parseDelayRemark(suc[i].assemble_end_date, suc[i].assemble_remark, array);

      sql = "select * from machining_sheet where type_flag = 1 and union_order = '"+ suc[i].union_order +"'";
      let succ2 = await db_util.query(sql);
      var jiagong = "";
      var ercijg = "";
      for(k=0; k<succ2.length; k++)
      {
        time += parseDelayRemark(succ2[k].code_end_date, succ2[k].code_remark, array);
        time += parseDelayRemark(succ2[k].end_date, succ2[k].machine_remark, array);
        time += parseDelayRemark(succ2[k].machine_end_date_2, succ2[k].machine_remark_2, array);

        if( succ2[k].end_date != '' && succ2[k].machine_remark != '' )
        {
          if( jiagong.length > 0 )
            jiagong += ";";
          jiagong += succ2[k].machine_remark.length;
        }
        if( succ2[k].machine_end_date_2 != '' && succ2[k].machine_remark_2 != '' )
        {
          if( ercijg.length > 0 )
            ercijg += ";";
          ercijg += succ2[k].machine_remark_2;
        }
      }

      if( time == 0 )
        continue;
      console.log('Delay ' + suc[i].union_order + ', ' + time + ' items, p79_id: ' + suc[i].p79_id);

      sql = "select * from p79_tofsms where id = '"+ suc[i].p79_id +"'";
      let succ3 = await db_util.query(sql);
      if( succ3.length > 0 )
      {
        var json = {};
        json["apply_date"] = succ3[0].ApplyDateTime.substr(0, 10);
        json["delivery_date"] = suc[i].delivery_date;
        json["apply_person"] = suc[i].apply_person;
        json["charge_department"] = suc[i].charge_department;
        json["unionorder"] = suc[i].union_order;
        json["sheji"] = suc[i].design_remark;
        json["jiagong"] = jiagong;
        json["ercijiagong"] = ercijg;
        json["zuzhuang"] = suc[i].assemble_remark;
        list.push(json);
      }
    }
    for(i=0; i<array.length; i++)
    {
      time = 0;
      for(k=0; k<array[i].data.length; k++)
      {
        time += array[i].data[k].count;
      }
      if( time > 0 )
      {
        var temp, sql;
        for(k=0; k<array[i].data.length; k++)
        {
          if( array[i].data[k].count == 0 )
            continue;
          temp = array[i].data[k].count * 100.0 / time; 
          sql = temp.toString();
          if( sql.indexOf('.') > 0 )
          {
            if( sql.split('.')[1].length > 1 )
              array[i].data[k].ratio = temp.toFixed(1);
            else
              array[i].data[k].ratio = sql;
          }
          else
          {
            array[i].data[k].ratio = sql + '.0';
          }
          array[i].data[k].ratio += '%';
        }
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array, "list":list});
  }
  catch(error)
  {
    console.log('QueryBaobiaoDelay error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})
// 领用明细报表
app.post('/QueryBaobiaoLingyong', async (req, res) => {
  try
  {
    var date = new Date();
    var starttime = 0;
    var endtime = date.getTime();
    if( req.body.starttime != undefined )
      starttime = Date.parse(req.body.starttime);
    if( req.body.endtime != undefined )
      endtime = Date.parse(req.body.endtime);
    var array = new Array();
    var i, j, k, time = 0;
    var sql = "select * from base_material";
    let material = await db_util.query(sql);
    sql = "select * from machining_union_sheet where lingqu_time != '' ORDER BY lingqu_time";
    let suc = await db_util.query(sql);
    for(i=0; i<suc.length; i++)
    {
      time = Date.parse(suc[i].lingqu_time);
      if( isNaN(time) )
        time = 0;
      if( time < starttime || time >= endtime )
        continue;
      date.setTime(time);
      sql = "select sheet_order, type, quatity_total, material_no, xuhao from machining_sheet where union_order = '"+ suc[i].union_order +"'";
      let succ2 = await db_util.query(sql);
      var material_type = "";
      var unit = "";
      var material_name = "";
      for(k=0; k<succ2.length; k++)
      {
        for(j=0; j<material.length; j++)
        {
          if( material[j].material_no == succ2[k].material_no )
          {
            material_type = material[j].type;
            unit = material[j].unit;
            material_name = material[j].name;
            break;
          }
        }
        var json = {};
        json["date"] = getMonthDayTime(date, 1);
        json["unionorder"] = suc[i].union_order;
        json["name"] = succ2[k].sheet_order;
        json["machine"] = suc[i].machine_type;
        json["xuhao"] = succ2[k].xuhao;
        json["type"] = succ2[k].type;
        json["workorder"] = material_name;
        json["material_no"] = succ2[k].material_no;
        json["material_type"] = material_type;
        json["quatity"] = succ2[k].quatity_total;
        json["unit"] = unit;
        json["charge"] = suc[i].charge_department;
        json["apply_person"] = suc[i].apply_person;
        json["cost"] = 0.0; // 材料费用
        sql = "select * from material_send where union_order = '"+ suc[i].union_order +"' and sheet_order = '"+ succ2[k].sheet_order +"'";
        let suc2 = await db_util.query(sql);
        for(j=0; j<suc2.length; j++)
        {
          var quatity = parseFloat(suc2[j].quatity);
          if( isNaN(quatity) )
            quatity = 0;
          if( quatity <= 0 )
            continue;
          var price = parseFloat(suc2[j].price);
          if( isNaN(price) )
          {
            console.log('查询料号税后价格：' + suc[i].union_order + ' - ' + suc2[j].material_no + '不存在');
            price = 0.0;
          }
          json["cost"] += quatity * price;
        }
        json["remark"] = "";
        array.push(json);
      }
    }

    suc = null;
    sql = "select * from material_apply where lingliao_riqi != '' ORDER BY lingliao_riqi";
    suc = await db_util.query(sql);
    for(i=0; i<suc.length; i++)
    {
      time = Date.parse(suc[i].lingqu_time);
      if( isNaN(time) )
        time = 0;
      if( time < starttime || time >= endtime )
        continue;
      for(j=0; j<material.length; j++)
      {
        if( material[j].material_no == suc[i].material_no )
        {
          material_type = material[j].type;
          unit = material[j].unit;
          material_name = material[j].name;
          break;
        }
      }
      var json = {};
      json["date"] = suc[i].lingliao_riqi;
      json["unionorder"] = suc[i].applyID;
      json["name"] = suc[i].applyType;
      json["machine"] = "";
      json["xuhao"] = "";
      json["type"] = suc[i].applyType;
      json["workorder"] = suc[i].name;
      json["material_no"] = suc[i].material_no;
      json["material_type"] = material_type;
      json["quatity"] = suc[i].quatity;
      json["unit"] = unit;
      json["charge"] = suc[i].charge_department;
      json["apply_person"] = suc[i].applicant;
      json["cost"] = 0.0; // 材料费用
      sql = "select * from material_send where union_order = '"+ suc[i].applyID +"'";
      let suc2 = await db_util.query(sql);
      for(j=0; j<suc2.length; j++)
      {
        var quatity = parseFloat(suc2[j].quatity);
        if( isNaN(quatity) )
          quatity = 0;
        if( quatity <= 0 )
          continue;
        var price = parseFloat(suc2[j].price);
        if( isNaN(price) )
        {
          console.log('查询料号税后价格：' + suc[i].applyID + ' - ' + suc2[j].material_no + '不存在');
          price = 0.0;
        }
        json["cost"] += quatity * price;
      }
      json["remark"] = "";
      array.push(json);
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoLingyong error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})
// 呆滞料报表：三个月未领用的物料统计
app.post('/QueryBaobiaoDaizhiliao', async (req, res) => {
  try
  {
    var date = new Date();
    var year = date.getFullYear();
    var month = date.getMonth();
    var day = date.getDate();
    if( month >= 3 )
    {
      month -= 3;
    }
    else
    {
      year --;
      month += 9;
    }
    var starttime = year + "-";
    if( month < 9 )
      starttime += "0";
    starttime += month;
    if( day < 10 )
      starttime += "0";
    starttime += day;
    starttime += " 00:00:00";

    var array = new Array();
    var sql = "select * from warehouse GROUP BY material_no";
    let suc = await db_util.query(sql);
    for(var i=0; i<suc.length; i++)
    {
      sql = "select * from material_send where quatity > 0 and timestamp > '"+ starttime +"' and material_no = '"+ suc[i].material_no +"' ORDER BY id DESC LIMIT 1";
      let succ2 = await db_util.query(sql);
      if( succ2.length > 0 )
        continue;
      sql = "select * from warehouse where material_no = '"+ suc[i].material_no +"' ORDER BY id DESC LIMIT 1";
      let succ3 = await db_util.query(sql);
      var json = {};
      json["PR_NO"] = succ3[0].PR_NO;
      json["PO_NO"] = succ3[0].PO_NO;
      json["SN"] = succ3[0].SN;
      json["material_no"] = succ3[0].material_no;
      json["quatity"] = succ3[0].quatity;
      json["price"] = succ3[0].price;
      json["manufacturer"] = succ3[0].manufacturer;
      json["currency"] = succ3[0].currency;
      json["check_no"] = succ3[0].check_no;
      json["reason"] = succ3[0].purchasing_reason;
      json["time"] = succ3[0].timestamp;
      array.push(json);
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoDaizhiliao error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

function getOTDWeek(date)
{
  var json = {};
  var dt = new Date(date);
  var day = date.getDate();
  var month = date.getMonth();
  if( day > 20 ) // 到下个月
  {
    dt.setMonth(month+1);
    json["month"] = getMonthDayTime(dt);
    if( day > 27 )
    {
      dt.setTime(date.getTime());
      dt.setDate(28);
      json["from"] = getMonthDayTime(dt, 1);
      dt.setTime(dt.getTime() + 6*24*3600*1000);
      json["to"] = getMonthDayTime(dt, 1);
    }
    else
    {
      json["from"] = getMonthDayTime(date) + '-21';
      json["to"] = getMonthDayTime(date) + '-27';
    }
  }
  else
  {
    json["month"] = getMonthDayTime(date);
    dt.setMonth(month-1);
    dt.setDate(28);
    json["from"] = getMonthDayTime(dt, 1);
    var currTime = dt.getTime() + 6*24*3600*1000;
    dt.setTime(currTime);
    var day2 = dt.getDate();
    if( day <= day2 )
    {
      json["to"] = getMonthDayTime(dt, 1);
    }
    else if( day <= (day2 + 7) )
    {
      currTime += 24*3600*1000;
      dt.setTime(currTime);
      json["from"] = getMonthDayTime(dt, 1);
      currTime += 6*24*3600*1000;
      dt.setTime(currTime);
      json["to"] = getMonthDayTime(dt, 1);
    }
    else
    {
      currTime += 8*24*3600*1000;
      dt.setTime(currTime);
      json["from"] = getMonthDayTime(dt, 1);
      dt.setDate(20);
      json["to"] = getMonthDayTime(dt, 1);
    }
  }
  dt.setTime(Date.parse(json["from"]));
  json["range"] = (dt.getMonth()+1) + '/' + dt.getDate() + '~';
  dt.setTime(Date.parse(json["to"]));
  json["range"] += ((dt.getMonth()+1) + '/' + dt.getDate());
  if( day > 20 ) // 到下个月
  {
    month ++;
    if( month > 11 )
      month = 0;
  }
  var arr = ['JAN.', 'FEB.', 'MAR.', 'APR.', 'MAY.', 'JUN.', 'JUL.', 'AUG.', 'SEP.', 'OCT.', 'NOV.', 'DEC.'];
  json["month_name"] = arr[month];
  return json;
}

app.post('/QueryBaobiaoOTD', async (req, res) => {
  try
  {
    var date = new Date();
    var i, j, k;
    var array = new Array();
    var sql = "select * from machining_union_sheet where ruku_time != '' ORDER BY delivery_date ASC";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"ok", "order":array});
      return;
    }
    var currentTime = Date.parse(suc[0].delivery_date);
    date.setTime(currentTime);
    var first = getOTDWeek(date);
    var json = {};
    json["month"] = first.month;
    json["month_name"] = first.month_name;
    json["data"] = new Array();
    var json2 = {};
    json2["from"] = first.from;
    json2["to"] = first.to;
    json2["range"] = first.range;
    json2["design_ok"] = 0;
    json2["design_delay"] = 0;
    json2["jiagong_ok"] = 0;
    json2["jiagong_delay"] = 0;
    json2["ercijg_ok"] = 0;
    json2["ercijg_delay"] = 0;
    json2["zuzhuang_ok"] = 0;
    json2["zuzhuang_delay"] = 0;
    json2["otd_ok"] = 0;
    json2["otd_delay"] = 0;
    json["data"].push(json2);
    array.push(json);
    if( suc.length > 1 )
    {
      date.setTime(Date.parse(suc[suc.length-1].delivery_date));
      var last = getOTDWeek(date);
      while( suc.length > 1 )
      {
        currentTime += 7*24*3600*1000;
        date.setTime(currentTime);
        first = getOTDWeek(date);
        if( first.to > last.to )
          break;
        for(i=0; i<array.length; i++)
        {
          if( array[i]["month"] == first.month )
          {
            for(k=0; k<array[i]["data"].length; k++)
            {
              if( array[i]["data"][k].range == first.range )
                break;
            }
            if( k == array[i]["data"].length )
            {
              var json2 = {};
              json2["from"] = first.from;
              json2["to"] = first.to;
              json2["range"] = first.range;
              json2["design_ok"] = 0;
              json2["design_delay"] = 0;
              json2["jiagong_ok"] = 0;
              json2["jiagong_delay"] = 0;
              json2["ercijg_ok"] = 0;
              json2["ercijg_delay"] = 0;
              json2["zuzhuang_ok"] = 0;
              json2["zuzhuang_delay"] = 0;
              json2["otd_ok"] = 0;
              json2["otd_delay"] = 0;
              array[i]["data"].push(json2);
            }
            break;
          }
        }
        if( i == array.length )
        {
          var json = {};
          json["month"] = first.month;
          json["month_name"] = first.month_name;
          json["data"] = new Array();
          var json2 = {};
          json2["from"] = first.from;
          json2["to"] = first.to;
          json2["range"] = first.range;
          json2["design_ok"] = 0;
          json2["design_delay"] = 0;
          json2["jiagong_ok"] = 0;
          json2["jiagong_delay"] = 0;
          json2["ercijg_ok"] = 0;
          json2["ercijg_delay"] = 0;
          json2["zuzhuang_ok"] = 0;
          json2["zuzhuang_delay"] = 0;
          json2["otd_ok"] = 0;
          json2["otd_delay"] = 0;
          json["data"].push(json2);
          array.push(json);
        }
      }
    }
    for(i=0; i<suc.length; i++)
    {
      date.setTime(Date.parse(suc[i].delivery_date));
      sql = "select * from machining_sheet where union_order = '"+ suc[i].union_order +"'";
      let succ2 = await db_util.query(sql);
      var jiagong_end_date = "";
      var ercijg_end_date = "";
      for(k=0; k<succ2.length; k++)
      {
        if( succ2[k].end_date > jiagong_end_date )
          jiagong_end_date = succ2[k].end_date;
        if( succ2[k].machine_end_date_2 > ercijg_end_date )
          ercijg_end_date = succ2[k].machine_end_date_2;
      }
      sql = getMonthDayTime(date);
      for(j=0; j<array.length; j++)
      {
        if( array[j]["month"] == sql )
        {
          first = getOTDWeek(date);
          for(k=0; k<array[j]["data"].length; k++)
          {
            if( array[j]["data"][k].range == first.range )
            {
              var time = Date.parse(suc[i].design_end_date);
              if( suc[i].sheji_endtime == '' )
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].sheji_endtime);
              if( currentTime > time )
              {
                array[j]["data"][k]["design_delay"] += 1;
                console.log('设计Delay：' + suc[i].union_order + '，期限：' + suc[i].design_end_date + '，结束：' + suc[i].sheji_endtime);
              }
              else
              {
                array[j]["data"][k]["design_ok"] += 1;
              }

              time = Date.parse(jiagong_end_date);
              if( suc[i].jiagong_endtime == '' )
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].jiagong_endtime);
              if( currentTime > time )
              {
                array[j]["data"][k]["jiagong_delay"] += 1;
                console.log('加工Delay：' + suc[i].union_order + '，期限：' + jiagong_end_date + '，结束：' + suc[i].jiagong_endtime);
              }
              else
              {
                array[j]["data"][k]["jiagong_ok"] += 1;
              }

              time = Date.parse(ercijg_end_date);
              if( suc[i].ercijg_endtime == '' )
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].ercijg_endtime);
              if( currentTime > time )
              {
                array[j]["data"][k]["ercijg_delay"] += 1;
                console.log('二次Delay：' + suc[i].union_order + '，期限：' + ercijg_end_date + '，结束：' + suc[i].ercijg_endtime);
              }
              else
              {
                array[j]["data"][k]["ercijg_ok"] += 1;
              }

              time = Date.parse(suc[i].assemble_end_date);
              if( suc[i].zuzhuang_endtime == '' )
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].zuzhuang_endtime);
              if( currentTime > time )
              {
                array[j]["data"][k]["zuzhuang_delay"] += 1;
                console.log('组装Delay：' + suc[i].union_order + '，期限：' + suc[i].assemble_end_date + '，结束：' + suc[i].zuzhuang_endtime);
              }
              else
              {
                array[j]["data"][k]["zuzhuang_ok"] += 1;
              }
              
              time = Date.parse(suc[i].delivery_date);
              if( suc[i].ruku_time == '' )
                currentTime = Date.now();
              else
                currentTime = Date.parse(suc[i].ruku_time);
              if( currentTime > time )
              {
                array[j]["data"][k]["otd_delay"] += 1;
                console.log('入库Delay：' + suc[i].union_order + '，期限：' + suc[i].delivery_date + '，结束：' + suc[i].ruku_time);
              }
              else
              {
                array[j]["data"][k]["otd_ok"] += 1;
              }
              break;
            }
          }
          break;
        }
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoOTD error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryBaobiaoBenefit', async (req, res) => {
  try
  {
    var date = new Date();
    var i, j, k, index;
    var array = new Array();
    var sql = "select * from machining_union_sheet where ruku_time != '' and price != '' ORDER BY ruku_time ASC";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"ok", "order":array});
      return;
    }
    var currentTime = Date.parse(suc[0].ruku_time);
    date.setTime(currentTime);
    var first = getOTDWeek(date);
    var json = {};
    json["month"] = first.month;
    json["month_name"] = first.month_name;
    json["data"] = new Array();
    var json2 = {};
    json2["from"] = first.from;
    json2["to"] = first.to;
    json2["range"] = first.range;
    json2["yingyee"] = 0;
    json2["cailiaofei"] = 0;
    json2["daojuhaocai"] = 0;
    json2["total_cost"] = 0;
    json["data"].push(json2);
    array.push(json);
    var starttime = first.from;
    var endtime = first.to;
    if( suc.length > 1 )
    {
      date.setTime(Date.parse(suc[suc.length-1].ruku_time));
      var last = getOTDWeek(date);
      endtime = last.to;
      while( suc.length > 1 )
      {
        currentTime += 7*24*3600*1000;
        date.setTime(currentTime);
        first = getOTDWeek(date);
        if( first.to > last.to )
          break;
        for(i=0; i<array.length; i++)
        {
          if( array[i]["month"] == first.month )
          {
            for(k=0; k<array[i]["data"].length; k++)
            {
              if( array[i]["data"][k].range == first.range )
                break;
            }
            if( k == array[i]["data"].length )
            {
              var json2 = {};
              json2["from"] = first.from;
              json2["to"] = first.to;
              json2["range"] = first.range;
              json2["yingyee"] = 0;
              json2["cailiaofei"] = 0;
              json2["daojuhaocai"] = 0;
              json2["total_cost"] = 0;
              array[i]["data"].push(json2);
            }
            break;
          }
        }
        if( i == array.length )
        {
          var json = {};
          json["month"] = first.month;
          json["month_name"] = first.month_name;
          json["data"] = new Array();
          var json2 = {};
          json2["from"] = first.from;
          json2["to"] = first.to;
          json2["range"] = first.range;
          json2["yingyee"] = 0;
          json2["cailiaofei"] = 0;
          json2["daojuhaocai"] = 0;
          json2["total_cost"] = 0;
          json["data"].push(json2);
          array.push(json);
        }
      }
    }
    for(i=0; i<suc.length; i++)
    {
      date.setTime(Date.parse(suc[i].ruku_time));
      sql = getMonthDayTime(date);
      for(j=0; j<array.length; j++)
      {
        if( array[j]["month"] == sql )
        {
          first = getOTDWeek(date);
          for(k=0; k<array[j]["data"].length; k++)
          {
            if( array[j]["data"][k].range == first.range )
            {
              sql = "select * from material_send where union_order = '"+ suc[i].union_order +"'";
              let succ2 = await db_util.query(sql);
              for(index=0;  index<succ2.length; index++)
              {
                var quatity = parseFloat(succ2[index].quatity);
                if( quatity <= 0 )
                  continue;
                array[j]["data"][k]["cailiaofei"] += quatity * parseFloat(succ2[index].price);
                array[j]["data"][k]["total_cost"] += quatity * parseFloat(succ2[index].price);
              }
              array[j]["data"][k]["yingyee"] += (parseInt(suc[i].quatity) * parseFloat(suc[i].price));
              break;
            }
          }
          break;
        }
      }
    }

    starttime += " 00:00:00";
    endtime += " 23:59:59";
    sql = "select * from material_send where sheet_order = '領用單' and timestamp >= '"+ starttime +"' and timestamp <= '"+ endtime +"'";
    let succ3 = await db_util.query(sql);
    for(i=0; i<succ3.length; i++)
    {
      var quatity = parseFloat(succ3[i].quatity);
      if( quatity <= 0 )
        continue;
      date.setTime(Date.parse(succ3[i].timestamp));
      sql = getMonthDayTime(date);
      for(j=0; j<array.length; j++)
      {
        if( array[j]["month"] == sql )
        {
          first = getOTDWeek(date);
          for(k=0; k<array[j]["data"].length; k++)
          {
            if( array[j]["data"][k].range == first.range )
            {
              array[j]["data"][k]["daojuhaocai"] += quatity * parseFloat(succ3[i].price);
              array[j]["data"][k]["total_cost"] += quatity * parseFloat(succ3[i].price);
             break;
            }
          }
          break;
        }
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryBaobiaoBenefit error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryBaobiaoBenefitPerFactory', async (req, res) => {
  try
  {
    var date = new Date();
    var i, j, k, index;
    var array = new Array();
    var factory = new Array();
    var sql = "select * from machining_union_sheet where ruku_time != '' and price != '' ORDER BY ruku_time ASC";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"ok", "order":array, "factory":factory});
      return;
    }
    sql = "select factory from machining_union_sheet where ruku_time != '' and price != '' GROUP BY factory ORDER BY factory";
    let succ2 = await db_util.query(sql);
    for(j=0; j<succ2.length; j++)
    {
      factory.push(succ2[j].factory);
    }
    var currentTime = Date.parse(suc[0].ruku_time);
    date.setTime(currentTime);
    var first = getOTDWeek(date);
    var json = {};
    json["month"] = first.month;
    json["month_name"] = first.month_name;
    json["data"] = new Array();
    var json2 = {};
    json2["from"] = first.from;
    json2["to"] = first.to;
    json2["range"] = first.range;
    json2["total"] = 0;
    json2["factory"] = new Array();
    for(j=0; j<succ2.length; j++)
    {
      var json3 = {};
      json3["name"] = succ2[j].factory;
      json3["cost"] = 0;
      json2["factory"].push(json3);
    }
    json["data"].push(json2);
    array.push(json);
    if( suc.length > 1 )
    {
      date.setTime(Date.parse(suc[suc.length-1].ruku_time));
      var last = getOTDWeek(date);
      endtime = last.to;
      while( suc.length > 1 )
      {
        currentTime += 7*24*3600*1000;
        date.setTime(currentTime);
        first = getOTDWeek(date);
        if( first.to > last.to )
          break;
        for(i=0; i<array.length; i++)
        {
          if( array[i]["month"] == first.month )
          {
            for(k=0; k<array[i]["data"].length; k++)
            {
              if( array[i]["data"][k].range == first.range )
                break;
            }
            if( k == array[i]["data"].length )
            {
              var json2 = {};
              json2["from"] = first.from;
              json2["to"] = first.to;
              json2["range"] = first.range;
              json2["total"] = 0;
              json2["factory"] = new Array();
              for(j=0; j<succ2.length; j++)
              {
                var json3 = {};
                json3["name"] = succ2[j].factory;
                json3["cost"] = 0;
                json2["factory"].push(json3);
              }
              array[i]["data"].push(json2);
            }
            break;
          }
        }
        if( i == array.length )
        {
          var json = {};
          json["month"] = first.month;
          json["month_name"] = first.month_name;
          json["data"] = new Array();
          var json2 = {};
          json2["from"] = first.from;
          json2["to"] = first.to;
          json2["range"] = first.range;
          json2["total"] = 0;
          json2["factory"] = new Array();
          for(j=0; j<succ2.length; j++)
          {
            var json3 = {};
            json3["name"] = succ2[j].factory;
            json3["cost"] = 0;
            json2["factory"].push(json3);
          }
          json["data"].push(json2);
          array.push(json);
        }
      }
    }
    for(i=0; i<suc.length; i++)
    {
      date.setTime(Date.parse(suc[i].ruku_time));
      sql = getMonthDayTime(date);
      for(j=0; j<array.length; j++)
      {
        if( array[j]["month"] == sql )
        {
          first = getOTDWeek(date);
          for(k=0; k<array[j]["data"].length; k++)
          {
            if( array[j]["data"][k].range == first.range )
            {
              var cost = parseInt(suc[i].quatity) * parseFloat(suc[i].price);
              for(index=0; index<array[j]["data"][k].factory.length; index++)
              {
                if( array[j]["data"][k].factory[index].name == suc[i].factory )
                {
                  array[j]["data"][k].factory[index].cost += cost;
                  array[j]["data"][k].total += cost;
                  break;
                }
              }
              if( index == array[j]["data"][k].factory.length )
              {
                var json = {};
                json["name"] = suc[i].factory;
                json["cost"] = cost;
                array[j]["data"][k].factory.push(json);
                array[j]["data"][k].total += cost;
              }
              break;
            }
          }
          break;
        }
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array, "factory":factory});
  }
  catch(error)
  {
    console.log('QueryBaobiaoBenefitPerFactory error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

// 生产排程总计划
app.post('/QueryProductionSchedulingPlan', async (req, res) => {
  try
  {
    var time = 0;
    var date = new Date();
    var array = new Array();
    var sql = "select * from machining_union_sheet where status = 0";
    let suc = await db_util.query(sql);
    for(var i=0; i<suc.length; i++)
    {
      var json = {};
      if( suc[i].status == '1' )
        json["status"] = "Close";
      else
      {
        if( suc[i].ruku_time != '' )
        {
          time = Date.parse(suc[i].ruku_time);
          if( isNaN(time) )
            time = Date.now();
        }
        else
        {
          time = Date.now();
        }
        date.setTime(time);
        var temp = getMonthDayTime(date, 1);
        if( temp > suc[i].delivery_date )
          json["status"] = "Delay";
        else
          json["status"] = "Ongoing";
      }
      json["factory"] = suc[i].factory;
      json["machine_type"] = suc[i].machine_type;
      json["name"] = suc[i].name;
      json["delivery_date"] = suc[i].delivery_date;
      json["apply_person"] = suc[i].apply_person;
      json["unionorder"] = suc[i].union_order;
      json["design_qixian"] = suc[i].design_end_date;
      if( suc[i].sheji_endtime == null )
        json["design_endtime"] = "";
      else if( suc[i].sheji_endtime.length > 10 )
        json["design_endtime"] = suc[i].sheji_endtime.substr(0, 10);
      else
        json["design_endtime"] = suc[i].sheji_endtime;
      json["code_qixian"] = "";
      if( suc[i].biancheng_endtime == null )
        json["code_endtime"] = "";
      else if( suc[i].biancheng_endtime.length > 10 )
        json["code_endtime"] = suc[i].biancheng_endtime.substr(0, 10);
      else
        json["code_endtime"] = suc[i].biancheng_endtime;
      json["jiagong_qixian"] = "";
      if( suc[i].jiagong_endtime == null )
        json["jiagong_endtime"] = "";
      else if( suc[i].jiagong_endtime.length > 10 )
        json["jiagong_endtime"] = suc[i].jiagong_endtime.substr(0, 10);
      else
        json["jiagong_endtime"] = suc[i].jiagong_endtime;
      json["ercijg_qixian"] = "";
      if( suc[i].ercijg_endtime == null )
        json["ercijg_endtime"] = "";
      else if( suc[i].ercijg_endtime.length > 10 )
        json["ercijg_endtime"] = suc[i].ercijg_endtime.substr(0, 10);
      else
        json["ercijg_endtime"] = suc[i].ercijg_endtime;
      json["zuzhuang_qixian"] = suc[i].assemble_end_date;
      if( suc[i].zuzhuang_endtime == null )
        json["zuzhuang_endtime"] = "";
      else if( suc[i].zuzhuang_endtime.length > 10 )
        json["zuzhuang_endtime"] = suc[i].zuzhuang_endtime.substr(0, 10);
      else
        json["zuzhuang_endtime"] = suc[i].zuzhuang_endtime;
      json["machine_remark"] = suc[i].machine_remark;
      json["delay_remark"] = "";
      sql = "select id, end_date, machine_remark, code_end_date, code_remark, machine_end_date_2, machine_remark_2 from machining_sheet where union_order = '"+ suc[i].union_order +"' and type_flag = 1";
      let succ2 = await db_util.query(sql);
      for(var k=0; k<succ2.length; k++)
      {
        if( succ2[k].end_date > json["jiagong_qixian"] )
          json["jiagong_qixian"] = succ2[k].end_date;
        if( succ2[k].code_end_date > json["code_qixian"] )
          json["code_qixian"] = succ2[k].code_end_date;
        if( succ2[k].machine_end_date_2 > json["ercijg_qixian"] )
          json["ercijg_qixian"] = succ2[k].machine_end_date_2;
        if( succ2[k].machine_remark != '' )
        {
          if( json["delay_remark"] != '' )
            json["delay_remark"] += ";";
          json["delay_remark"] += succ2[k].machine_remark;
        }
        if( succ2[k].code_remark != '' )
        {
          if( json["delay_remark"] != '' )
            json["delay_remark"] += ";";
          json["delay_remark"] += succ2[k].code_remark;
        }
        if( succ2[k].machine_remark_2 != '' )
        {
          if( json["delay_remark"] != '' )
            json["delay_remark"] += ";";
          json["delay_remark"] += succ2[k].machine_remark_2;
        }
      }
      array.push(json);
    }
    
    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryProductionSchedulingPlan error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})
// 设计/编程/二次加工/组装/品检/标准件备料/总检/CNC设备生产进度
app.post('/QuerySegmentSchedule', async (req, res) => {
  try
  {
    var sql = "";
    var array = new Array();
    if( req.body.segment == "design" )
    {
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        if( suc[i].stage.charAt(0) == '0' ) // 已完成
          continue;
        var json = {};
        if( suc[i].engineer == '' )
          json["status"] = "待設計";
        else
          json["status"] = "設計中";
        json["factory"] = suc[i].factory;
        json["machine_type"] = suc[i].machine_type;
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["engineer"] = suc[i].engineer;
        json["delivery_date"] = suc[i].delivery_date;
        json["design_qixian"] = suc[i].design_end_date;
        json["design_endtime"] = suc[i].sheji_endtime;
        array.push(json);
      }
    }
    else if( req.body.segment == "code" )
    {
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        if( suc[i].stage.charAt(1) == '0' ) // 已完成
          continue;
        var json = {};
        json["status"] = "編程中";
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["code_qixian"] = "";
        sql = "select id, end_date, code_end_date, machine_end_date_2 from machining_sheet where union_order = '"+ suc[i].union_order +"' and type_flag = 1 and status = 1";
        let succ2 = await db_util.query(sql);
        for(var k=0; k<succ2.length; k++)
        {
          if( succ2[k].code_end_date > json["code_qixian"] )
            json["code_qixian"] = succ2[k].code_end_date;
        }
        array.push(json);
      }
    }
    else if( req.body.segment == "ercijg" )
    {
      var engineer = "";
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        if( suc[i].stage.charAt(4) == '0' ) // 已完成
          continue;
        var json = {};
        json["status"] = "加工中";
        json["ercijg_qixian"] = "";
        sql = "select id, machine_end_date_2, engineer_ercijiagong from machining_sheet where union_order = '"+ suc[i].union_order +"' and type_flag = 1 and status = 4";
        let succ2 = await db_util.query(sql);
        for(var k=0; k<succ2.length; k++)
        {
          if( succ2[k].machine_end_date_2 > json["ercijg_qixian"] )
            json["ercijg_qixian"] = succ2[k].machine_end_date_2;
          if( succ2[k].engineer_ercijiagong != '' )
          {
            if( engineer.length > 0 )
              engineer += ",";
            engineer += succ2[k].engineer_ercijiagong;
          }
        }
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["engineer"] = engineer;
        array.push(json);
        engineer = "";
      }
    }
    else if( req.body.segment == "pinjian" )
    {
      sql = "select * from machining_union_sheet where status = 0";
      let suc = await db_util.query(sql);
      var i, j, k;
      for(i=0; i<suc.length; i++)
      {
        if( suc[i].stage.charAt(3) == '0' ) // 已完成
          continue;
        sql = "select sheet_order, check_status, quatity_total from machining_sheet where union_order = '"+ suc[i].union_order +"' and status = 3";
        let succ2 = await db_util.query(sql);
        sql = "select songjian_shijian, box, ljmc, gjjcjg from dispatch_sheet where union_order = '"+ suc[i].union_order +"' and status = 3";
        let succ3 = await db_util.query(sql);
        for(k=0; k<succ3.length; k++)
        {
          if( succ3[k].songjian_shijian == '' )
            continue;
          var json = {};
          json["status"] = "";
          json["check_date"] = succ3[k].songjian_shijian;
          json["box"] = succ3[k].box;
          json["name"] = suc[i].name;
          json["image_no"] = succ3[k].ljmc;
          json["quatity_total"] = "0";
          json["ok_count"] = "0";
          json["ng_count"] = "0";
          if( succ3[k].gjjcjg != '' )
          {
            j = succ3[k].gjjcjg.indexOf(',');
            if( j > 0 )
            {
              json["ng_count"] = succ3[k].gjjcjg.slice(0, j);
              json["ok_count"] = succ3[k].gjjcjg.slice(j+1);
            }
          }
          for(j=0; j<succ2.length; j++)
          {
            if( succ2[j].sheet_order == succ3[k].ljmc )
            {
              json["status"] = succ2[j].check_status;
              json["quatity_total"] =  succ2[j].quatity_total;
              break;
            }
          }
          json["unionorder"] = suc[i].union_order;
          json["delivery_date"] = suc[i].delivery_date;
          if( json["quatity_total"] != json["ok_count"] || json["ng_count"] != "0" )
            array.push(json);
        }
      }
    }
    else if( req.body.segment == "zuzhuang" )
    {
      var i, k;
      sql = "select * from machining_union_sheet where status = 0 and stage like '_____1%'";
      let suc = await db_util.query(sql);
      for(i=0; i<suc.length; i++)
      {
        sql = "select status from machining_sheet where union_order = '"+ suc[i].union_order +"' and type_flag = 1";
        let succ2 = await db_util.query(sql);
        for(k=0; k<succ2.length; k++)
        {
          if( succ2[k].status != 5 )
            break;
        }
        if( k < succ2.length ) // 还有加工件没有到组装阶段
          continue;
        var json = {};
        json["status"] = "組裝中";
        json["zuzhuang_qixian"] = suc[i].assemble_end_date;
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["engineer"] = suc[i].engineer_zuzhuang;
        array.push(json);
      }
    }
    else if( req.body.segment == "zongjian" )
    {
      sql = "select * from machining_union_sheet where status = 0 and ruku_time = ''";
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        if( suc[i].quatity == suc[i].zongjian_ok_count || suc[i].songjian_time == '' )
          continue;
        var json = {};
        json["status"] = "";
        json["songjian_time"] = suc[i].songjian_time;
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["quatity"] = suc[i].quatity;
        json["code19"] = suc[i].code19;
        json["ng_count"] = suc[i].zongjian_ng_count;
        json["ok_count"] = suc[i].zongjian_ok_count;
        json["delivery_date"] = suc[i].delivery_date;
        array.push(json);
      }
    }
    else if( req.body.segment == "beiliao" )
    {
      sql = "select union_order, name, delivery_date from machining_union_sheet where status = 0 and length(engineer) > 0 ORDER BY delivery_date ASC";
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        sql = "select sheet_order, material_no, beiliao_ztai from machining_sheet where union_order = '"+ suc[i].union_order +"' and type_flag = 0";
        let suc2 = await db_util.query(sql);
        var status1 = 0, status2 = 0, status3 = "";
        for(var k=0; k<suc2.length; k++)
        {
          if( suc2[k].beiliao_ztai == 2 )
          {
            status2 ++;
          }
          else if( suc2[k].beiliao_ztai == 3 )
          {
            if( status3.length > 0 )
              status3 += ",";
            status3 += suc2[k].sheet_order;
          }
          else
          {
            status1 ++;
          }
        }
        var json = {};
        if( status3.length > 0 )
          json["status"] = "缺料";
        else if( status1 > 0 )
          json["status"] = "備料中";
        else
          continue;//json["status"] = "已備料";
        json["unionorder"] = suc[i].union_order;
        json["name"] = suc[i].name;
        json["yibei"] = status2;
        json["queliao"] = (suc2.length - status1 - status2);
        json["delivery_date"] = suc[i].delivery_date;
        json["remark"] = status3;
        array.push(json);
      }

      sql = "select * from material_apply where checker != ''"; // 签核后才显示
      let suc4 = await db_util.query(sql);
      for(var i=0; i<suc4.length; i++)
      {
        if( suc4[i].lingliao_riqi != '' || suc4[i].beiliao_ztai == 2 )
          continue;
        var json = {};
        if( suc4[i].beiliao_ztai == 3 )
          json["status"] = "缺料";
        else if( suc4[i].beiliao_ztai == 2 )
          json["status"] = "已備料";
        else
          json["status"] = "備料中";
        json["unionorder"] = suc4[i].applyID;
        json["name"] = suc4[i].name;
        json["yibei"] = suc4[i].yibei_shuliang;
        json["queliao"] = 0;
        json["delivery_date"] = "";
        json["remark"] = "";
        var stock = parseInt(suc4[i].stock);
        if( isNaN(stock) )
          stock = 0;
        var yibei = parseInt(suc4[i].yibei_shuliang);
        if( isNaN(yibei) )
          yibei = 0;
        var tuiku = parseInt(suc4[i].tuiku_shuliang);
        if( isNaN(tuiku) )
          tuiku = 0;
        stock += tuiku;
        tuiku = parseInt(suc4[i].quatity);
        if( isNaN(tuiku) )
          tuiku = 0;
        if( stock < tuiku )
          json["queliao"] = tuiku - stock;
        array.push(json);
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QuerySegmentSchedule error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryWorkhour', async (req, res) => {
  try
  {
    var i, j, k;
    var array = new Array();
    let suc = await db_util.query("select * from workhour");
    for(i=0; i<suc.length; i++)
    {
      for(k=0; k<array.length; k++)
      {
        if( array[k].type == suc[i].type )
        {
          for(j=0; j<array[k].arr.length; j++)
          {
            if( array[k].arr[j].kind == suc[i].kind )
            {
              var json = {};
              json["keypoint"] = suc[i].keypoint;
              json["value"] = suc[i].value;
              json["kg"] = false;
              array[k].arr[j].arr.push(json);
              break;
            }
          }
          if( j == array[k].arr.length )
          {
            if( suc[i].keypoint == '' )
            {
              var json3 = {};
              json3["kind"] = suc[i].kind;
              json3["基本工時"] = suc[i].value;
              json3["arr"] = new Array();
              array[k].arr.push(json3);
            }
            else
            {
              var arr = new Array();
              var json2 = {};
              json2["keypoint"] = suc[i].keypoint;
              json2["value"] = suc[i].value;
              json["kg"] = false;
              arr.push(json2);
              var json3 = {};
              json3["kind"] = suc[i].kind;
              json3["arr"] = arr;
              array[k].arr.push(json3);
            }
          }
          break;
        }
      }
      if( k == array.length )
      {
        var json = {};
        json["type"] = suc[i].type;
        json["arr"] = new Array();
        var json3 = {};
        json3["kind"] = suc[i].kind;
        json3["基本工時"] = suc[i].value;
        json3["arr"] = new Array();
        json["arr"].push(json3);
        array.push(json);
      }
    }

    res.status(200);
    res.json({"result":"ok", "order":array});
  }
  catch(error)
  {
    console.log('QueryWorkhour error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryDailyWorkhour', async (req, res) => {
  try
  {
    var json = {};
    var sql = "select * from cncother where name = 'workhour'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      json["design"] = 20;
      json["code"] = 20;
      json["jiagong"] = 20;
      json["ercijiagong"] = 20;
      json["zuzhuang"] = 20;
      await db_util.query("insert into cncother values ('workhour', '20', 'design', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'code', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'jiagong', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'ercijiagong', '')");
      await db_util.query("insert into cncother values ('workhour', '20', 'zuzhuang', '')");
    }
    else
    {
      for(var i=0; i<suc.length; i++)
      {
        json[suc[i].remark] = suc[i].value;
      }
    }
    json["result"] = "ok";
    res.status(200);
    res.json(json);
  }
  catch(error)
  {
    console.log('QueryDailyWorkhour error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateDailyWorkhour', async (req, res) => {
  try
  {
    var i = 0;
    var sql = "select * from cncother where name = 'workhour'";
    let suc = await db_util.query(sql);
    if( req.body.design != undefined )
    {
      for(i=0; i<suc.length; i++)
      {
        if( suc[i].remark == 'design' )
          break;
      }
      if( i == suc.length )
        sql = "insert into cncother (name, value, remark) values ('workhour', '"+ req.body.design +"', 'design')";
      else
        sql = "update cncother set value = '"+ req.body.design +"' where name = 'workhour' and remark = 'design'";
      await db_util.query(sql);
    }
    if( req.body.code != undefined )
    {
      for(i=0; i<suc.length; i++)
      {
        if( suc[i].remark == 'code' )
          break;
      }
      if( i == suc.length )
        sql = "insert into cncother (name, value, remark) values ('workhour', '"+ req.body.code +"', 'code')";
      else
        sql = "update cncother set value = '"+ req.body.code +"' where name = 'workhour' and remark = 'code'";
      await db_util.query(sql);
    }
    if( req.body.jiagong != undefined )
    {
      for(i=0; i<suc.length; i++)
      {
        if( suc[i].remark == 'jiagong' )
          break;
      }
      if( i == suc.length )
        sql = "insert into cncother (name, value, remark) values ('workhour', '"+ req.body.jiagong +"', 'jiagong')";
      else
        sql = "update cncother set value = '"+ req.body.jiagong +"' where name = 'workhour' and remark = 'jiagong'";
      await db_util.query(sql);
    }
    if( req.body.ercijiagong != undefined )
    {
      for(i=0; i<suc.length; i++)
      {
        if( suc[i].remark == 'ercijiagong' )
          break;
      }
      if( i == suc.length )
        sql = "insert into cncother (name, value, remark) values ('workhour', '"+ req.body.ercijiagong +"', 'ercijiagong')";
      else
        sql = "update cncother set value = '"+ req.body.ercijiagong +"' where name = 'workhour' and remark = 'ercijiagong'";
      await db_util.query(sql);
    }
    if( req.body.zuzhuang != undefined )
    {
      for(i=0; i<suc.length; i++)
      {
        if( suc[i].remark == 'zuzhuang' )
          break;
      }
      if( i == suc.length )
        sql = "insert into cncother (name, value, remark) values ('workhour', '"+ req.body.zuzhuang +"', 'zuzhuang')";
      else
        sql = "update cncother set value = '"+ req.body.zuzhuang +"' where name = 'workhour' and remark = 'zuzhuang'";
      await db_util.query(sql);
    }
 
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('UpdateDailyWorkhour error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryTasktable', async (req, res) => {
  try
  {
    var date = new Date();
    var cost_time = date.getTime();
    var array = new Array();
    var i, j, k;
    var design = 0, code = 0;
    var jiagong = 0, ercijg = 0, zuzhuang = 0;
    let sucData = await db_util.query("select * from cncother where name = 'workhour'");
    for(i=0; i<sucData.length; i++)
    {
      if( sucData[i].remark == 'design' )
        design = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'code' )
        code = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'jiagong' )
        jiagong = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'ercijiagong' )
        ercijg = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'zuzhuang' )
        zuzhuang = parseFloat(sucData[i].value);
    }
    for(i=0; i<30; i++)
    {
      date.setTime(cost_time + i * 24 * 3600 * 1000);
      var json = {};
      json["date"] = getMonthDayTime(date, 1);//(date.getMonth() + 1) + "/" + date.getDate();
      json["design"] = {};
      json["design"]["set_workhour"] = design;
      json["design"]["estimate_hour"] = 0;
      json["design"]["total_hour"] = 0;
      json["design"]["hit"] = false;
      json["design"]["tasks"] = new Array();
      json["code"] = {};
      json["code"]["set_workhour"] = code;
      json["code"]["estimate_hour"] = 0;
      json["code"]["total_hour"] = 0;
      json["code"]["hit"] = false;
      json["code"]["tasks"] = new Array();
      json["jiagong"] = {};
      json["jiagong"]["set_workhour"] = jiagong;
      json["jiagong"]["estimate_hour"] = 0;
      json["jiagong"]["total_hour"] = 0;
      json["jiagong"]["hit"] = false;
      json["jiagong"]["tasks"] = new Array();
      json["ercijiagong"] = {};
      json["ercijiagong"]["set_workhour"] = ercijg;
      json["ercijiagong"]["estimate_hour"] = 0;
      json["ercijiagong"]["total_hour"] = 0;
      json["ercijiagong"]["hit"] = false;
      json["ercijiagong"]["tasks"] = new Array();
      json["zuzhuang"] = {};
      json["zuzhuang"]["set_workhour"] = zuzhuang;
      json["zuzhuang"]["estimate_hour"] = 0;
      json["zuzhuang"]["total_hour"] = 0;
      json["zuzhuang"]["hit"] = false;
      json["zuzhuang"]["tasks"] = new Array();
      array.push(json);
    }
    var sql = "select * from autoschedule";
    let suc = await db_util.query(sql);
    for(i=0; i<suc.length; i++)
    {
      sql = "select * from task_sheet where id = '"+ suc[i].id +"'";
      let suc2 = await db_util.query(sql);
      for(k=0; k<suc2.length; k++)
      {
        for(j=0; j<array.length; j++)
        {
          if( array[j]["date"] == suc2[k].date )
          {
            break;
          }
        }
        if( j >= array.length )
          continue;
        sql = suc2[k].task + "_workhour";
        var json = {};
        json["name"] = suc[i].name;
        json["delivery_date"] = suc[i].delivery_date;
        json["quatity"] = suc[i].quatity;
        json["workhour"] = suc2[k].workhour;
        json["date"] = suc2[k].date;
        json["task"] = suc2[k].task;
        json["estimate_workhour"] = suc[i][sql];
        json["total_workhour"] = 0;
        for(var n=0; n<suc2.length; n++)
        {
          if( suc2[n].task == suc2[k].task )
          {
            json["total_workhour"] += parseFloat(suc2[n].workhour);
          }
        }
        array[j][suc2[k].task]["tasks"].push(json);
        array[j][suc2[k].task]["estimate_hour"] = parseFloat(suc[i][sql]);
        array[j][suc2[k].task]["total_hour"] += parseFloat(suc2[k].workhour);
      }
    }
    res.status(200);
    res.json({"result":"ok","order":array});
  } 
  catch(error)
  {
    console.log('QueryTasktable error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/AddTask', async (req, res) => {
  try
  {
    var date = new Date();
    var today = getMonthDayTime(date, 1);
    var body = req.body;
    var design = 0, code = 0;
    var jiagong = 0, ercijg = 0, zuzhuang = 0;
    let sucData = await db_util.query("select * from cncother where name = 'workhour'");
    for(var i=0; i<sucData.length; i++)
    {
      if( sucData[i].remark == 'design' )
        design = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'code' )
        code = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'jiagong' )
        jiagong = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'ercijiagong' )
        ercijg = parseFloat(sucData[i].value);
      if( sucData[i].remark == 'zuzhuang' )
        zuzhuang = parseFloat(sucData[i].value);
    }
    var i, j, k;
    var array = new Array();
    var arrTask = new Array();
    date.setTime(date.getTime() + 5*24*3600*1000);
    var sql = "select id from autoschedule where delivery_date > '"+ getMonthDayTime(date, 1) +"'";
    var suc3 = await db_util.query(sql);
    for(i=0; i<suc3.length; i++)
    {
      sql = "select * from task_sheet where id = '"+ suc3[i].id +"'";
      let suc2 = await db_util.query(sql);
      for(k=0; k<suc2.length; k++)
      {
        for(j=0; j<array.length; j++)
        {
          if( array[j]["date"] == suc2[k].date )
          {
            array[j][suc2[k].task] += parseFloat(suc2[k].workhour);
            break;
          }
        }
        if( j == array.length )
        {
          var json = {};
          json["date"] = suc2[k].date;
          json["design"] = 0;
          json["code"] = 0;
          json["jiagong"] = 0;
          json["ercijiagong"] = 0;
          json["zuzhuang"] = 0;
          json[suc2[k].task] = parseFloat(suc2[k].workhour);
          array.push(json);
        }
      }
    }
    var endtime = Date.parse(body.end_date) - 24 * 3600 * 1000; // 交期的前一天
    date.setTime(endtime);
    if( date.getDay() == 0 ) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    var taskdate = getMonthDayTime(date, 1);
    // 一、安排组装
    j = parseFloat(body.zuzhuang_workhour);
    if( isNaN(j) )
    {
      res.status(200);
      res.json({"result":"error", "description":"组装工时异常。"});
      return;
    }
    while(true)
    {
      i = zuzhuang;
      for(k=0; k<array.length; k++)
      {
        if( array[k]["date"] == taskdate )
        {
          i -= array[k]["zuzhuang"];
          break;
        }
      }
      if( i >= j )
      {
        var json = {};
        json["date"] = taskdate;
        json["task"] = "zuzhuang";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else
      {
        if( i > 0 )
        {
          var json = {};
          json["date"] = taskdate;
          json["task"] = "zuzhuang";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24*3600*1000);
        if( date.getDay() == 0 ) // 周日
          date.setTime(date.getTime() - 24*3600*1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if( taskdate <= today )
    {
      console.log('组装工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({"result":"error", "description":"组装工期不足。"});
      return;
    }

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if( date.getDay() == 0 ) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 二、安排二次加工
    j = parseFloat(body.ercijiagong_workhour);
    if( isNaN(j) )
    {
      res.status(200);
      res.json({"result":"error", "description":"二次加工工时异常。"});
      return;
    }
    while(true)
    {
      i = ercijg;
      for(k=0; k<array.length; k++)
      {
        if( array[k]["date"] == taskdate )
        {
          i -= array[k]["ercijiagong"];
          break;
        }
      }
      if( i >= j )
      {
        var json = {};
        json["date"] = taskdate;
        json["task"] = "ercijiagong";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else
      {
        if( i > 0 )
        {
          var json = {};
          json["date"] = taskdate;
          json["task"] = "ercijiagong";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24*3600*1000);
        if( date.getDay() == 0 ) // 周日
          date.setTime(date.getTime() - 24*3600*1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if( taskdate <= today )
    {
      console.log('二次加工工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({"result":"error", "description":"二次加工工期不足。"});
      return;
    }

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if( date.getDay() == 0 ) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 三、安排加工
    j = parseFloat(body.jiagong_workhour);
    if( isNaN(j) )
    {
      res.status(200);
      res.json({"result":"error", "description":"加工工时异常。"});
      return;
    }
    while(true)
    {
      i = jiagong;
      for(k=0; k<array.length; k++)
      {
        if( array[k]["date"] == taskdate )
        {
          i -= array[k]["jiagong"];
          break;
        }
      }
      if( i >= j )
      {
        var json = {};
        json["date"] = taskdate;
        json["task"] = "jiagong";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else
      {
        if( i > 0 )
        {
          var json = {};
          json["date"] = taskdate;
          json["task"] = "jiagong";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24*3600*1000);
        if( date.getDay() == 0 ) // 周日
          date.setTime(date.getTime() - 24*3600*1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if( taskdate <= today )
    {
      console.log('加工工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({"result":"error", "description":"加工工期不足。"});
      return;
    }

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if( date.getDay() == 0 ) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 四、安排编程
    j = parseFloat(body.code_workhour);
    if( isNaN(j) )
    {
      res.status(200);
      res.json({"result":"error", "description":"编程工时异常。"});
      return;
    }
    while(true)
    {
      i = code;
      for(k=0; k<array.length; k++)
      {
        if( array[k]["date"] == taskdate )
        {
          i -= array[k]["code"];
          break;
        }
      }
      if( i >= j )
      {
        var json = {};
        json["date"] = taskdate;
        json["task"] = "code";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else
      {
        if( i > 0 )
        {
          var json = {};
          json["date"] = taskdate;
          json["task"] = "code";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24*3600*1000);
        if( date.getDay() == 0 ) // 周日
          date.setTime(date.getTime() - 24*3600*1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if( taskdate <= today )
    {
      console.log('编程工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({"result":"error", "description":"编程工期不足。"});
      return;
    }

    endtime = Date.parse(taskdate) - 24 * 3600 * 1000;
    // 各项任务不可以在同一天
    date.setTime(endtime);
    if( date.getDay() == 0 ) // 周日
    {
      endtime -= 24 * 3600 * 1000;
      date.setTime(endtime);
    }
    taskdate = getMonthDayTime(date, 1);
    // 五、安排设计
    j = parseFloat(body.design_workhour);
    if( isNaN(j) )
    {
      res.status(200);
      res.json({"result":"error", "description":"设计工时异常。"});
      return;
    }
    while(true)
    {
      i = design;
      for(k=0; k<array.length; k++)
      {
        if( array[k]["date"] == taskdate )
        {
          i -= array[k]["design"];
          break;
        }
      }
      if( i >= j )
      {
        var json = {};
        json["date"] = taskdate;
        json["task"] = "design";
        json["workhour"] = j;
        arrTask.push(json);
        break;
      }
      else
      {
        if( i > 0 )
        {
          var json = {};
          json["date"] = taskdate;
          json["task"] = "design";
          json["workhour"] = i;
          arrTask.push(json);
          j -= i;
        }
        date.setTime(date.getTime() - 24*3600*1000);
        if( date.getDay() == 0 ) // 周日
          date.setTime(date.getTime() - 24*3600*1000);
        taskdate = getMonthDayTime(date, 1);
      }
    }
    if( taskdate <= today )
    {
      console.log('设计工期不足，最后日期：' + taskdate);
      res.status(200);
      res.json({"result":"error", "description":"设计工期不足。"});
      return;
    }


    sql = "select * from autoschedule where name = '"+ body.name +"'";
    let suc = await db_util.query(sql);
    if( suc.length > 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":"同名的治具名称已存在。"});
      return;
    }
    else
    {
      sql = "insert into autoschedule values(null, '"+ body.name +"', '"+ body.type +"', '"+ body.delivery_date +"',\
            '"+ body.end_date +"', '"+ body.quatity +"', '"+ body.design_workhour +"', '"+ body.code_workhour +"',\
            '"+ body.jiagong_workhour +"', '"+ body.ercijiagong_workhour +"', '"+ body.zuzhuang_workhour +"')";
    }
    let suc4 = await db_util.query(sql);
    if( suc4.affectedRows > 0 )
    {
      for(i=0; i<arrTask.length; i++)
      {
        sql = "insert into task_sheet values ('"+ suc4.insertId +"', '"+ arrTask[i]["task"] +"', '"+ arrTask[i]["date"] +"', '"+ arrTask[i]["workhour"] +"')";
        await db_util.query(sql);
      }
    }

    res.status(200);
    res.json({"result":"ok"});
  } 
  catch(error)
  {
    console.log('AddTask error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/DeleteTask', async (req, res) => {
  try
  {
    var sql = "select id from autoschedule where name = '"+ req.body.name +"'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":"not find the name"});
      return;
    }
    sql = "delete from task_sheet where id = '"+ suc[0].id +"'";
    await db_util.query(sql);
    sql = "delete from autoschedule where id = '"+ suc[0].id +"'";
    await db_util.query(sql);

    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('DeleteTask error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/UpdateTask', async (req, res) => {
  if( req.body.date == undefined || req.body.task == undefined )
  {
    res.status(200);
    res.json({"result":"error", "description":"not find the date or task"});
    return;
  }
  try
  {
    var sql = "select * from autoschedule where name = '"+ req.body.name +"'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      res.status(200);
      res.json({"result":"error", "description":"not find the name"});
      return;
    }
    var where = " where id = '"+ suc[0].id +"' and task = '"+ req.body.task +"' and date = '"+ req.body.date +"'";
    if( req.body.dateNew != undefined && req.body.dateNew != req.body.date )
    {
      var workhour = 0;
      if( req.body.workhour != undefined )
      {
        workhour = parseFloat(req.body.workhour);
      }
      else
      {
        sql = "select workhour from task_sheet" + where;
        let suc2 = await db_util.query(sql);
        if( suc2.length > 0 )
          workhour = parseFloat(suc2[0].workorder);
      }
      sql = "delete from task_sheet" + where;
      await db_util.query(sql);
      where = " where id = '"+ suc[0].id +"' and task = '"+ req.body.task +"' and date = '"+ req.body.dateNew +"'";
      sql = "select workhour from task_sheet" + where;
      let suc3 = await db_util.query(sql);
      if( suc3.length == 0 )
      {
        sql = "insert into task_sheet values ('"+ suc[0].id +"', '"+ req.body.task +"', '"+ req.body.dateNew +"', '"+ workhour +"')";
      }
      else
      {
        workhour += parseFloat(suc3[0].workhour);
        sql = "update task_sheet set workhour = '"+ workhour +"'" + where;
      }
      let suc4 = await db_util.query(sql);
      if( suc4.affectedRows == 0 )
      {
        console.log('failed: ' + sql);
      }
    }
    else if( req.body.workhour != undefined )
    {
      sql = "update task_sheet set workhour = '"+ req.body.workhour +"'" + where;
      await db_util.query(sql);
      console.log(sql);
    }
    res.status(200);
    res.json({"result":"ok"});
  }
  catch(error)
  {
    console.log('UpdateTask error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})

app.post('/QueryAlarmInfo', async (req, res) => {
  try
  {
    var cost_time = 0;
    var date = new Date();
    var hour = date.getHours();
    if( hour < 8 )
    {
      setTime(date, 0);
      cost_time = date.getTime() - 4 * 3600 * 1000;
    }
    else if( hour < 20 ) // 白班
    {
      setTime(date, 8);
      cost_time = date.getTime();
    }
    else
    {
      setTime(date, 20);
      cost_time = date.getTime();
    }
    if( req.body.starttime != undefined )
      cost_time = Date.parse(req.body.starttime);
    var array = new Array();
    var sql = "select * from cncalarm where name = 'alarm-"+ req.body.MachineName +"' and Time >= '"+ cost_time +"' and reason != ''";
    let suc = await db_util.query(sql);
    for(var i=0; i<suc.length; i++)
    {
      var json = {};
      json["reason"] = suc[i].alarmMsg;
      json["time"] = suc[i].alarmTime;
      json["reply"] = suc[i].reason;
      json["pic"] = suc[i].pic;
      array.push(json);
    }

    res.status(200);
    res.json({"result":"ok","order":array});
  } 
  catch(error)
  {
    console.log('QueryAlarmInfo error: ' + error.message);
    res.status(200);
    res.json({"result":"error", "description":error.message});
  }
})



var httpServer = http.createServer(function(req, res){
  var url = decodeURI(req.url);
  if(req.method.toUpperCase() == "GET")
  {
    var index = url.lastIndexOf('/');
    var fileName = url.substr(index+1);
    var filePath = "./public" + url;
    try
    {
      //console.log('Visit: ' + url);
      var stats = fs.statSync(filePath);
      if(stats.isFile())
      {
        res.writeHead(200, {
          "Content-type":"application/octet-stream",
          "Content-Disposition":"attachment;filename="+encodeURI(fileName),
          "Content-Length":stats.size
        });
        var fReadStream = fs.createReadStream(filePath);
        fReadStream.on("data", function(chunk) {res.write(chunk, "binary")});
        fReadStream.on("end", function() {res.end()});
      }
      else
      {
        res.writeHead(200, {"Content-type": "text/html"});
        res.write("file not exist!");
        res.end();
      }
    }
    catch(err)
    {
      res.writeHead(200, {"Content-type": "text/html"});
      res.write(err.message);
      res.end();
    }
    //console.log('The address you visited: ' + url);
  }
  else if(req.method.toLowerCase() == "post")
  {
    var form = formidable.IncomingForm();
    form.uploadDir = "./public";
    form.keepExtensions = false;
    form.parse(req, function(err, fields, files){
      if(err)
        throw err;
      res.writeHead(200, {'content-type':'text/plain'});
      res.end("success");
    });
  }
});

async function intervalFunc() {
  if( g_cncInfo == undefined )
    return;
  if( g_cncInfo.length < 1 )
  {
    loadCNC();
    return;
  }
  var date = new Date();
  var hour = date.getHours();
  if( date.getDate() == 1 && hour < 3 && hour >= 0 )
  {
    try
    {
      var dt = new Date(date);
      var year = dt.getFullYear();
      var mon = dt.getMonth();
      dt.setMonth(mon - 1);
      var month = getMonthDayTime(dt);
      var sql = "select * from cncmonth where month = '"+ month +"' and name = ''";
      let suc = await db_util.query(sql);
      if( suc.length > 0 && suc[0].last_id.length == 0 )
        return;
      var starttime = month + '-01 00:00:00';
      var endtime = year + '-';
      if( mon < 9 )
        endtime += '0' + (mon + 1) + '-01 00:00:00';
      else
        endtime += (mon + 1) + '-01 00:00:00';
      let ret = await StatisticOee(undefined, starttime, endtime);
      if( ret["result"] == "ok" )
      {
        if( suc.length == 0 )
          sql = "insert into cncmonth (month, oee, oee15, run_time, total_time, total_time_15, last_time, last_id) values('"+ month +"', '"+ ret["oee1"] +"', '"+ ret["oee15"] +"', '"+ ret["run_time"] +"', '"+ ret["total_time"] +"', '"+ ret["total_time_15"] +"', '"+ ret["last_time"] +"', '')";
        else
          sql = "update cncmonth set oee = '"+ ret["oee1"] +"', oee15 = '"+ ret["oee15"] +"', run_time = '"+ ret["run_time"] +"', total_time = '"+ ret["total_time"] +"', total_time_15 = '"+ ret["total_time_15"] +"', last_time = '"+ ret["last_time"] +"', last_id = '' where month = '"+ month +"'";
        await db_util.query(sql);

        sql = "delete from cncmonth where month = '"+ month +"' and length(name) > 0";
        await db_util.query(sql);
        if( ret["order"] != undefined )
        {
          for(var i=0; i<ret["order"].length; i++)
          {
            sql = "insert into cncmonth values('"+ month +"', '"+ g_cncInfo[i].MachineName +"', '"+ ret["order"][i]["oee1"] +"', '"+ ret["order"][i]["oee15"] +"', '"+ ret["order"][i]["run_time"] +"', '"+ ret["order"][i]["total_time"] +"', '"+ ret["order"][i]["total_time_15"] +"', '"+ ret["order"][i]["last_time"] +"', '')";
            await db_util.query(sql);
          }
        }
      }
    }
    catch(error)
    {
      console.log('save month data error: ' + error.message);
    }
  }

  if( date.getDay() == 0 && hour >= 0 && hour < 2 )
  {
    var week = getYearWeek(date.getTime() - 5*3600*1000);
    var sql = "select * from cncother where name = 'cncweek'";
    try
    {
      var flag = true;
      let suc = await db_util.query(sql);
      if( suc.length > 0 )
      {
        if( suc[0].value == week )
          flag = false;
      }
      if( flag )
      {
        var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        dt.setTime(dt.getTime() - 7*24*3600*1000);
        var starttime = getMonthDayTime(dt, 1, 1);
        let ret = await StatisticOeeWeek(null, starttime);
        if( ret.length > 0 )
        {
          if( suc.length > 0 )
            sql = "update cncother set value = '"+ week +"' where name = 'cncweek'";
          else
            sql = "insert into cncother (name, value) values('cncweek', '"+ week +"')";
          await db_util.query(sql);
        }
      }
    }
    catch(error)
    {
      console.log('save week data error: ' + error.message);
    }
  }

  // 检查是否有文件过期需要删除
  if( hour > 0 && hour < 3 )
  {
    var sql = "select * from machining_files where length(union_order) > 10";
    try
    {
      var temp = 0;
      var dt = new Date();
      var days = parseInt(db_util.config.file_lifetime);
      if( isNaN(days) )
        days = 365;
      else if( days < 30 )
        days = 30;
      days = days * 24 * 3600 * 1000;
      var currentTime = Date.now();
      let suc = await db_util.query(sql);
      for(var i=0; i<suc.length; i++)
      {
        temp = Date.parse(suc[i].upload_time);
        if( isNaN(temp) )
          continue;
        temp += days;
        if( temp > currentTime )
          continue;
        sql = suc[i].file_path;
        fs.unlink(sql, function(err) {
          if( err )
          {
            console.log('Check file lifetime: failed to delete file: ' + sql);
          }
          else
          {
            console.log('Check file lifetime: succeeded to delete file: ' + sql);
          }
        });
        temp = sql.lastIndexOf('.');
        if( temp < 1 )
          continue;
        var ext = sql.substr(temp+1).toLowerCase();
        if( ext != 'xlsx' && ext != 'xls' )
          continue;
        sql = "./public/" + suc[i].union_order + "/images";
        if( fs.existsSync(sql) == false )
          continue;
        fs.readdirSync(sql).forEach(function(file) {
          ext = sql + "/" + file;
          if( fs.statSync(ext).isDirectory() == false )
          {
            fs.unlinkSync(ext);
          }
        });
      }
    }
    catch(error)
    {
      console.log('check file lifetime error: ' + error.message);
    }
  }

  //if( date.getDay() == 0 && hour > 21 )
  if( (date.getTime() - g_lastUpdateTime) > g_nWaitTime && g_cncInfo[0].reserved2 != 88 )
  {
    g_cncInfo[0].reserved2 = 88;
    try
    {
      var id = 0;
      let ret = await db_util.query("select * from cncother where name = 'checkid'");
      if( ret.length > 0 )
      {
        id = parseInt(ret[0].value);
        if( isNaN(id) )
          id = 0;
        else if( id < 1 )
          id = 0;
      }
      var sql = "";
      var checkid = 2147483647;
      var cost_time = date.getTime();
      var wait_time = g_nOffTime * 8 / 10;
      for(var i=0; i<g_cncInfo.length; i++)
      {
        sql = "select id, evt_type, Time, Operation_Mode, operatingstatus, operatingmode, alarmstatus from cncdata where MachineName = '"+ g_cncInfo[i].MachineName +"'";
        if( id > 0 )
          sql += " and id >= '"+ id +"'";
        var currentTime = 0;
        var initialTime = 0;
        var last_time = 0;
        var last_evt_type = "";
        var last_mode = "";
        var last_status = "";
        var last_operMode = "";
        var last_alarm = "";
        var count = 0;
        var array = new Array();
        let suc = await db_util.query(sql);
        if( suc.length > 20 )
        {
          for(var k=0; k<suc.length; k++)
          {
            currentTime = parseInt(suc[k].Time);
            if( last_time == 0 || currentTime > (last_time + 21000) || last_evt_type != suc[k].evt_type ||
                last_mode != suc[k].Operation_Mode || last_status != suc[k].operatingstatus ||
                last_operMode != suc[k].operatingmode || last_alarm != suc[k].alarmstatus )
            {
              initialTime = currentTime;
              last_evt_type = suc[k].evt_type;
              last_mode = suc[k].Operation_Mode;
              last_status = suc[k].operatingstatus;
              last_operMode = suc[k].operatingmode;
              last_alarm = suc[k].alarmstatus;
            }
            else if( currentTime > (initialTime + wait_time) ) // 这个不删，免得误以为是超时停机
            {
              initialTime = currentTime;
            }
            else if( (k+1) < suc.length ) // 最后一条不要删除
            {
              count ++;
              array.push(suc[k].id);
              if( array.length >= 512 )
              {
                sql = "delete from cncdata where id in (";
                for(var j=0; j<array.length; j++)
                {
                  if( j > 0 )
                    sql += ",";
                  sql += "'"+ array[j] +"'";
                }
                sql +=")";
                await db_util.query(sql);
                array.length = 0;
              }
            }
            last_time = currentTime;
          }
          if( array.length > 0 )
          {
            sql = "delete from cncdata where id in (";
            for(var j=0; j<array.length; j++)
            {
              if( j > 0 )
                sql += ",";
              sql += "'"+ array[j] +"'";
            }
            sql +=")";
            await db_util.query(sql);
          }
          console.log(g_cncInfo[i].MachineName + ': ' + count + '/' + suc.length + ' = ' + parseInt(count*100/suc.length));
          if( suc[suc.length-1].id < checkid )
          {
            checkid = suc[suc.length-1].id;
          }
        }
      }
      if( checkid > id && checkid < 2147483647 )
      {
        if( ret.length > 0 )
          sql = "update cncother set value = '"+ checkid +"' where name = 'checkid'";
        else
          sql = "insert into cncother (name, value) values('checkid', '"+ checkid +"')";
        await db_util.query(sql);
      }
      cost_time = Date.now() - cost_time;
      if( checkid < 2147483647 )
        console.log('check data end, cost time ' + cost_time);
    }
    catch(error)
    {
      console.log('压缩数据出错：' + error.message);
    }
    g_cncInfo[0].reserved2 = 8;
  }
}

async function StatisticTool()
{
  var array = new Array();
  try
  {
    var sql = "select id, MachineName, Time, program, activetoolid from cncdata where Operation_Mode = 'Run' and length(activetoolid) > 0 and length(program) > 0";
    let tools = await db_util.query("select * from cnctool");
    if( tools == undefined )
    {
      console.log('StatisticTool failed');
      return array;
    }
    if( tools.length > 0 )
      sql += " and id > "+ tools[0].lastID +"";
    sql += " ORDER BY Time ASC";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
      return array;

    var arrIndex = {};
    for(var i=0; i<g_cncInfo.length; i++)
    {
      var json = {};
      json["MachineName"] = g_cncInfo[i].MachineName;
      json["lastTool"] = "";
      json["tools"] = new Array();
      array.push(json);
      arrIndex[g_cncInfo[i].MachineName] = i;
    }
    var index = -1;
    var currentTime = 0;
    var lastID = 0;
    for(var k=0; k<suc.length; k++)
    {
      if( suc[k].id > lastID )
        lastID = suc[k].id;
      index = arrIndex[suc[k].MachineName];
      if( isNaN(index) )
        continue;
      if( suc[k].activetoolid == "0" )
        continue;
      currentTime = parseInt(suc[k].Time);
      var i = -1;
      for(var m=0; m<array[index].tools.length; m++)
      {
        if( suc[k].activetoolid == array[index].tools[m].toolID )
        {
          i = m;
          break;
        }
      }
      if( array[index]["lastTool"].length > 0 && array[index]["lastTool"] != suc[k].activetoolid ) // 换刀号了
      {
        array[index]["lastTool"] = suc[k].activetoolid;
        if( i >= 0 )
          array[index].tools[i]["lastTime"] = 0;
      }
      // 判断是否有关机过程
      if( i >= 0 )
      {
        if( array[index].tools[i]["lastTime"] > 0 && (currentTime - array[index].tools[i]["lastTime"]) > g_nOffTime ) // 间隔时间大于10分钟
        {
          array[index].tools[i]["lastTime"] = 0;
        }
        if( array[index].tools[i]["lastTime"] > 0 && currentTime > array[index].tools[i]["lastTime"] )
          array[index].tools[i]["used_time"] += (currentTime - array[index].tools[i]["lastTime"]);
        array[index].tools[i]["lastTime"] = currentTime;
      }
      else
      {
        var json = {};
        json["toolID"] = suc[k].activetoolid;
        json["used_time"] = 0;
        json["lastTime"] = currentTime;
        for(var n=0; n<tools.length; n++)
        {
          if( tools[n].MachineName == suc[k].MachineName && tools[n].toolID == suc[k].activetoolid )
          {
            json["used_time"] = tools[n].used_time * 1000;
            if( (currentTime - tools[n].lastTime) < g_nOffTime && currentTime > tools[n].lastTime ) // 有可能有重复，低于上一次的时间就不计了
            {
              json["used_time"] += (currentTime - tools[n].lastTime);
            }
            break;
          }
        }
        array[index].tools.push(json);
      }
    }
    for(var i=0; i<array.length; i++)
    {
      for(var j=0; j<array[i].tools.length; j++)
      {
        index = -1;
        for(var k=0; k<tools.length; k++)
        {
          if( tools[k].MachineName == array[i].MachineName && tools[k].toolID == array[i].tools[j].toolID )
          {
            index = parseInt(array[i].tools[j].used_time/1000 + 0.5);
            sql = "update cnctool set lastTime = '"+ array[i].tools[j].lastTime +"', used_time = "+ index +", ";
            sql += "lastID = "+ lastID +" where id = "+ tools[k].id +"";
            await db_util.query(sql);
            index = k;
            break;
          }
        }
        if( index < 0 )
        {
          index = parseInt(array[i].tools[j].used_time/1000 + 0.5);
          sql = "insert into cnctool values(null, '"+ array[i].MachineName +"', '"+ array[i].tools[j].lastTime +"', ";
          sql += "'"+ array[i].tools[j].toolID +"', "+ index +", 0, "+ lastID +")";
          await db_util.query(sql);
        }
      }
    }
  }
  catch(error)
  {
    console.log('StatisticTool: ' + error.message);
  }
  return array;
}

let request = require('request');
const { json } = require('express');
const { totalmem } = require('os');
const { WSAEDESTADDRREQ, SSL_OP_NO_QUERY_MTU, SSL_OP_SSLEAY_080_CLIENT_DH_BUG } = require('constants');
const { resolve } = require('path');
const { DefaultDeserializer } = require('v8');

let sendHttpRequest = function(uri, data)
{
  return new Promise((resolve, reject) =>
  {
    //定义请求消息url和头部
    var options = {
      uri:'',
      method:'POST',
      timeout:3000,
      headers:{
        'Content-type':'application/json;charset=UTF-8',
        'Content-Length': Buffer.byteLength(data)
      },
      body:data
    };
    options["uri"] = uri;
    request(options, (err, response, body) => {
      if( err )
      {
        reject(err);
      }
      else
      {
        if( body["replyUserId"] != undefined )
          console.log(body);
        resolve(body);
      }
    });
  });
}

async function execute_http_request(index, msg, level, time, name)
{
  //定义消息body eventName: WKS B7_治具室CNC監控系統報警
  var body = {
    "site":'WKS',
    "Plant":'WKS',
    "eventId":'FRCNC001',
    "eventType":'0',
    "syncId":'',
    "alertType":0,
    "alertItem":1,
    "issueType":0,
    "uId":'',
    "status":0,
    "level":'L4',
    "shortMessage":'',
    "eventTime":'',
    "evtvalue1":'WKS',  // 厂别
    "evtvalue2":'null', // 线别
    "evtvalue3":'',     // 机种
    "evtvalue4":'',     // 设备名称
    "evtvalue5":'',     // 设备编号
    "evtvalue6":'',     // 故障描述
    "evtvalue7":'',     // 故障时间
    "evtvalue8":'10min',
    "pic":'',
    "mPic":'',
    "mPicPhone":'',
    "userId":'',
    "actionId":'',
    "comment":'',
    "extendDate":'',
    "replyUserId":'',
    "replyUserName":'',
    "replyDate":'',
    "toDMC":1,
    "toNotify":1
  };

  var date = new Date();
  body["level"] = level;
  body["syncId"] = g_cncInfo[index].name;
  body["eventTime"] = date.getTime().toString();
  body["evtvalue3"] = g_cncInfo[index].MachineModel;
  body["evtvalue4"] = g_cncInfo[index].MachineName;
  body["evtvalue5"] = g_cncInfo[index].MachineNO;
  body["evtvalue6"] = msg;
  body["evtvalue7"] = time;
  body["shortMessage"] = body["evtvalue1"] + '報警，线别：null，機種：' + body["evtvalue3"] + '，設備：' + body["evtvalue4"] + '，設備編號：' + body["evtvalue5"] + '，故障描述：' + body["evtvalue6"];

  try
  {
    var data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.wx_url, data);
    console.log('alarm: ' + g_cncInfo[index].MachineName + ' ' + msg + ' on ' + getMonthDayTime(date, 1, 1));
    
    body["alertType"] = 1;
    data = JSON.stringify(body);
    var sql = "select remark from cncother where name = '"+ name +"'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      sql = "insert into cncother values('"+ name +"', '"+ data +"', '1', '"+ body["eventTime"] +"')";
    }
    else
    {
      var count = parseInt(suc[0].remark);
      if( isNaN(count) )
        count = 1;
      count ++;
      sql = "update cncother set value = '"+ data +"', remark = '"+ count +"' where name = '"+ name +"'";
    }
    let suc2 = await db_util.query(sql);
    if( suc.length == 0 ) // 加到报警记录表中
    {
      sql = "insert into cncalarm (name, MachineName, Time, alarmMsg, alarmTime) values('"+ name +"', '"+ g_cncInfo[index].MachineName +"', '"+ body["eventTime"] +"', '"+ msg +"', '"+ time +"')";
      let suc3 = await db_util.query(sql);
    }
  }
  catch(error)
  {
    console.log(msg + ' ' + name + ' on ' + time + ' 异常：' + error.message);
  }
}

async function execute_http_request_datastream(index, msg, level, time, name)
{
  //定义消息body eventName: WKS B7_治具室CNC監控系統報警
  var body = {
    "site":'WKS',
    "Plant":'WKS',
    "eventId":'FRCNC001',
    "eventType":'0',
    "syncId":'',
    "alertType":0,
    "alertItem":1,
    "issueType":0,
    "uId":'',
    "status":0,
    "level":'L4',
    "shortMessage":'',
    "eventTime":'',
    "evtvalue1":'WKS',  // 厂别
    "evtvalue2":'null', // 线别
    "evtvalue3":'',     // 机种
    "evtvalue4":'',     // 设备名称
    "evtvalue5":'',     // 设备编号
    "evtvalue6":'',     // 故障描述
    "evtvalue7":'',     // 故障时间
    "evtvalue8":'3min',
    "pic":'',
    "mPic":'',
    "mPicPhone":'',
    "userId":'',
    "actionId":'',
    "comment":'',
    "extendDate":'',
    "replyUserId":'',
    "replyUserName":'',
    "replyDate":'',
    "toDMC":1,
    "toNotify":1
  };

  var date = new Date();
  body["level"] = level;
  body["syncId"] = "CNC监控系统数据流监控";
  body["eventTime"] = date.getTime().toString();
  body["evtvalue3"] = "null";
  body["evtvalue4"] = "CNC监控系统数据流监控";
  body["evtvalue5"] = "null";
  body["evtvalue6"] = msg;
  body["evtvalue7"] = time;
  body["shortMessage"] = body["evtvalue1"] + '報警，线别：null，機種：' + body["evtvalue3"] + '，設備：' + body["evtvalue4"] + '，設備編號：' + body["evtvalue5"] + '，故障描述：' + body["evtvalue6"];

  try
  {
    var data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.wx_url, data);
    console.log('alarm: 数据流监控 ' + msg + ' on ' + getMonthDayTime(date, 1, 1));
    
    body["alertType"] = 1;
    data = JSON.stringify(body);
    var sql = "select remark from cncother where name = '"+ name +"'";
    let suc = await db_util.query(sql);
    if( suc.length == 0 )
    {
      sql = "insert into cncother values('"+ name +"', '"+ data +"', '1', '"+ body["eventTime"] +"')";
    }
    else
    {
      var count = parseInt(suc[0].remark);
      if( isNaN(count) )
        count = 1;
      count ++;
      sql = "update cncother set value = '"+ data +"', remark = '"+ count +"' where name = '"+ name +"'";
    }
    let suc2 = await db_util.query(sql);
    if( suc.length == 0 ) // 加到报警记录表中
    {
      sql = "insert into cncalarm (name, MachineName, Time, alarmMsg, alarmTime) values('"+ name +"', '数据流监控', '"+ body["eventTime"] +"', '"+ msg +"', '"+ time +"')";
      let suc3 = await db_util.query(sql);
    }
  }
  catch(error)
  {
    console.log('http request datastream error: ' + error.message);
  }
}

async function execute_http_request_2(data, msg)
{
  try
  {
    var date = new Date();
    let ret = await sendHttpRequest(db_util.config.wx_url, data);
    console.log('alarm: ' + msg + ' on ' + getMonthDayTime(date, 1, 1));
  }
  catch(error)
  {
    console.log('http request 2 error: ' + error.message);
  }
}

async function execute_http_request_benefit_1(evt_dt, alarm_count, pay_hr)
{
  var body = {
    "evt_dt":'',
    "freq":'D',
    "site":'WKS',
    "company":'WSD',
    "plant":'WKS-5',
    "plant_code":'F232',
    "system_id":'smtcnc',
    "type_id":'equipment_maintenanc',
    "benefit_type":'direct',
    "params":[
      {
        "name":'alarm_count',
        "value":0,
        "type":'VAR'
      },
      {
        "name":'repair_time',
        "value":0.02,
        "type":'CONST'
      },
      {
        "name":'dl_pay_hr',
        "value":0,
        "type":'VAR'
      }
    ]
  };
  body["evt_dt"] = evt_dt;
  body["params"][0].value = alarm_count;
  body["params"][2].value = pay_hr;

  try
  {
    var data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.qas_url, data);
    var json = JSON.parse(ret);
    if( json["status"] == 200 )
    {
      console.log('###### 设备维修对接效益平台 OK：' + JSON.stringify(json) + '，效益：' + alarm_count + ' x ' + pay_hr);
      return "ok";
    }
    else
    {
      console.log('###### 设备维修对接效益平台 报错：' + json["errors"]);
      return json["errors"];
    }
  }
  catch(error)
  {
    console.log('###### 设备维修对接效益平台 出错: ' + error.message);
    return error.message;
  }
}

async function execute_http_request_benefit_2(evt_dt, download_count, pay_hr)
{
  var body = {
    "evt_dt":'',
    "freq":'D',
    "site":'WKS',
    "company":'WSD',
    "plant":'WKS-5',
    "plant_code":'F232',
    "system_id":'smtcnc',
    "type_id":'report_time',
    "benefit_type":'direct',
    "params":[
      {
        "name":'download_count',
        "value":0,
        "type":'VAR'
      },
      {
        "name":'report_time',
        "value":1,
        "type":'CONST'
      },
      {
        "name":'idl_pay_hr',
        "value":0,
        "type":'VAR'
      }
    ]
  };
  body["evt_dt"] = evt_dt;
  body["params"][0].value = download_count;
  body["params"][2].value = pay_hr;

  try
  {
    var data = JSON.stringify(body);
    let ret = await sendHttpRequest(db_util.config.qas_url, data);
    var json = JSON.parse(ret);
    if( json["status"] == 200 )
    {
      console.log('###### 制作报表时间对接效益平台 OK' + '，效益：' + download_count + ' x ' + pay_hr);
      return "ok";
    }
    else
    {
      console.log('###### 制作报表时间对接效益平台 报错：' + json["errors"]);
      return json["errors"];
    }
  }
  catch(error)
  {
    console.log('###### 制作报表时间接效益平台 出错: ' + error.message);
    return error.message;
  }
}

let benefit_get_laborcost = function(type)
{
  return new Promise((resolve, reject) => {
    var url = "http://benefit-api-wsd.api.10.42.226.2.k8sprd-wks.k8s.wistron.com/api/BenefitLaborCosts/latestCost?site=wks&plant=f232&type=" + type;
    request(url, function (err, response, body) {
      if( err )
      {
        //reject(err);
        console.log(err.message);
        var json = {};
        json["type"] = type;
        if( type == "DL" )
          json["cost"] = '22';
        else
          json["cost"] = '33.81';
        resolve(json);
      }
      else
      {
        resolve(body);
      }
    });
  });
}

let query_qiyeweixin_huifu = function(starttime, endtime)
{
  return new Promise((resolve, reject) => {
    var url = "http://webap01.wks.wistron.com.cn:3010/api/DmcEvents?filter[where][STime][between][0]=" + starttime;
    url += "&filter[where][STime][between][1]=" + endtime + "&filter[where][toDMC]=1&filter[where][System]=wks&filter[where][eventId]=FRCNC001";
    request(url, function (err, response, body) {
      if( err )
      {
        reject(err);
      }
      else
      {
        resolve(body);
      }
    });
  });
}

async function addAlarmCount(alarm_count)
{
  var sql = "";
  let ret = await db_util.query("select * from cncother where name = 'alarmcount'");
  if( ret.length > 0 )
  {
    var count = parseInt(ret[0].value);
    if( isNaN(count) )
      count = 0;
    alarm_count += count;
  }
  if( ret.length == 0 )
    sql = "insert into cncother (name, value) values('alarmcount', '"+ alarm_count +"')";
  else
    sql = "update cncother set value = '"+ alarm_count +"' where name = 'alarmcount'";
  await db_util.query(sql);
}

async function intervalAlarm() {
  var date = new Date();
  var hour = date.getHours();
  if( isIdleTime(date) == true )
    return;
  // 对接效益平台
  try
  {
    if( hour >= 0 && hour < 1 )
    {
      var check = false;
      var riqi = getMonthDayTime(date, 1);
      let xiaoyipingtai = await db_util.query("select * from cncother where name = 'xiaoyipingtai'");
      if( xiaoyipingtai.length == 0 )
        check = true;
      else if( xiaoyipingtai[0].value != riqi )
        check = true;
      if( check == true )
      {
        let DL = await benefit_get_laborcost('DL');
        let IDL = await benefit_get_laborcost('IDL');
        var cost_DL = JSON.parse(DL);
        var cost_IDL = JSON.parse(IDL);
        console.log(getMonthDayTime(date, 1, 1) + ': query loborcost, DL - ' + cost_DL["cost"] + ', IDL - ' + cost_IDL["cost"]);
        
        var alarm_count = 0;
        let alct = await db_util.query("select * from cncother where name = 'alarmcount'");
        if( alct.length > 0 )
        {
          alarm_count = parseInt(alct[0].value);
          if( isNaN(alarm_count) )
            alarm_count = 0;
        }
        var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        var evt_dt = dt.getTime() - 24 * 3600 * 1000;
        let alarm_ret = await execute_http_request_benefit_1(evt_dt, alarm_count, cost_DL["cost"]);
        
        alarm_count = 0;
        let dload = await db_util.query("select * from cncother where name = 'downloadcount'");
        if( dload.length > 0 )
        {
          alarm_count = parseInt(dload[0].value);
          if( isNaN(alarm_count) )
            alarm_count = 0;
        }
        let download_ret = await execute_http_request_benefit_2(evt_dt, alarm_count, cost_IDL["cost"]);

        var sql = "";
        if( alarm_ret == 'ok' && download_ret == 'ok' )
        {
          if( xiaoyipingtai.length == 0 )
            sql = "insert into cncother (name, value) values('xiaoyipingtai', '"+ riqi +"')";
          else
            sql = "update cncother set value = '"+ riqi +"' where name = 'xiaoyipingtai'";
          await db_util.query(sql);
        }
        if( alarm_ret == 'ok' )
        {
          sql = "update cncother set value = '0' where name = 'alarmcount'";
          await db_util.query(sql);
        }
        if( download_ret == 'ok' )
        {
          sql = "update cncother set value = '0' where name = 'downloadcount'";
          await db_util.query(sql);
        }
      }
    }
  }
  catch(error)
  {
    console.log('对接效益平台 error: ' + error.message + ' on ' + getMonthDayTime(date, 1, 1));
  }
  
  // 每个整点时间点检查上一个小时的单台设备稼动率/OEE是否低于目标值
  if( date.getMinutes() < 10 )
  {
    var check = false;
    let alarmtime = await db_util.query("select * from cncother where name = 'alarmtime'");
    if( alarmtime.length == 0 )
      check = true;
    else if( parseInt(alarmtime[0].value) != hour )
      check = true;
    if( check == true )
    {
      var sql = "";
      if( alarmtime.length == 0 )
        sql = "insert into cncother (name, value) values('alarmtime', '"+ hour +"')";
      else
        sql = "update cncother set value = '"+ hour +"' where name = 'alarmtime'";
      await db_util.query(sql);
      var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate(), hour);
      var st = new Date(dt.getTime() - 3600 * 1000);
      var starttime = getMonthDayTime(st, 1, 1);
      var endtime = getMonthDayTime(dt, 1, 1);
      console.log('检查上一个小时的单台设备稼动率 ' + getMonthDayTime(date, 1, 1));
      let rows = await StatisticUtilization(undefined, starttime, endtime);
      let target = await db_util.query("select * from cncother where name = 'jiadonglvValue'");
      var value = 80;
      if( target.length > 0 )
        value = parseInt(target[0].value);
      var alarm_count = 0;
      for(var i=0; i<rows.length; i++)
      {
        if( rows[i].total_time < 1 )
          continue;
        var jiadonglv = parseInt(rows[i].run_time/(rows[i].total_time/100));
        if( isNaN(jiadonglv) )
        {
          console.log(rows[i].MachineName + '稼动率计算异常！total_time = ' + rows[i].total_time);
          jiadonglv = value;
        }
        console.log(rows[i].MachineName + '稼动率：' + jiadonglv);
        var name = "alarm-" + g_cncInfo[i].MachineName;
        if( jiadonglv < value )
        {
          alarm_count ++;
          var level = 'L4';
          sql = "select remark from cncother where name = '"+ name +"'";
          let suc = await db_util.query(sql);
          if( suc.length > 0 )
          {
            var count = parseInt(suc[0].remark);
            if( isNaN(count) )
              count = 1;
            if( count >= 3 )
              level = 'L1';
            else if( count == 2 )
              level = 'L2';
            else
              level = 'L3';
          }
          await execute_http_request(i, "稼动率低于标准值", level, starttime, name);
        }
        else
        {
          sql = "select * from cncother where name = '"+ name +"'";
          let suc = await db_util.query(sql);
          if( suc.length > 0 )
          {
            alarm_count ++;
            var alarm_time = suc[0].reserved;
            var msg = g_cncInfo[i].MachineName + " 警报解除";
            await execute_http_request_2(suc[0].value, msg);

            sql = "delete from cncother where name = '"+ name +"'";
            await db_util.query(sql);
            
            msg = getMonthDayTime(date, 1, 1) + " 警报解除";
            sql = "update cncalarm set status = '"+ msg +"' where Time = '"+ alarm_time +"'";
            await db_util.query(sql);
          }
        }
      }
      if( alarm_count > 0 )
      {
        await addAlarmCount(alarm_count);
      }
    }
  }
  
  // 刀号累计使用时间统计
  try
  {
    var alarm_count = 0;
    let array = new Array(); //await StatisticTool(); // 暂时停掉2020/11/04 14:10
    for(var i=0; i<array.length; i++)
    {
      for(var j=0; j<array[i].tools.length; j++)
      {
        var used_time = array[i].tools[j].used_time/3600000;
        var allow_time = 24;
        var toolID = parseInt(array[i].tools[j].toolID);
        if( toolID > 10 )
          continue;
        if( toolID == 1 )
          allow_time = 60; // 钨钢倒角刀D6*90*50 2F
        else if( toolID == 2 || toolID == 3 || toolID == 4 )
          allow_time = 80; // 铣刀，钨钢铝用刀2*4*50 2F/3*3*50 3F/4*4*50 2F
        else if( toolID == 5 || toolID == 9 || toolID == 10 )
          allow_time = 100; // 铣刀，钨钢铝用刀6*6*50 2F/8*8*60 3F/6*6*50 2F
        else if( toolID == 6 )
          allow_time = 6; // 麻花钻头D2.5
        else if( toolID == 7 || toolID == 8 )
          allow_time = 8; // 麻花钻头D3.3/D4.2
        if( used_time < allow_time )
          continue;
        
        var sql = "select * from cnctool where MachineName = '"+ array[i].MachineName +"' and toolID = '"+ array[i].tools[j].toolID +"'";
        let rows = await db_util.query(sql);
        if( rows.length > 0 && used_time >= rows[0].alarm_status )
        {
          var send_alarm = false;
          var level = 'L4';
          var name = "alarm-" + array[i].MachineName + "-toolID" + toolID;
          sql = "select remark, reserved, value from cncother where name = '"+ name +"'";
          let suc1 = await db_util.query(sql);
          if( suc1.length > 0 )
          {
            var count = parseInt(suc1[0].remark);
            if( isNaN(count) )
              count = 1;
            var obj = JSON.parse(suc1[0].value);
            var last_send_time = parseInt(obj.eventTime);
            if( isNaN(last_send_time) )
              last_send_time = date.getTime();

            if( (date.getTime() - last_send_time) >= 15*60*1000 ) // 超过15分钟
            {
              send_alarm = true;
              if( count >= 3 )
                level = 'L1';
              else if( count == 2 )
                level = 'L2';
              else
                level = 'L3';
            }
            else
            {
              if( count >= 4 )
              {
                alarm_count ++;
                var msg = array[i].MachineName + " 刀号" + array[i].tools[j].toolID + " 警报解除 自动";
                await execute_http_request_2(suc1[0].value, msg);
                sql = "delete from cncother where name = '"+ name +"'";
                await db_util.query(sql);

                last_send_time = parseInt(suc1[0].reserved); // 第一次报警的时间，同时作为cncalarm表中的记录识别标记
                msg = getMonthDayTime(date, 1, 1) + " 警报解除 自动";
                sql = "update cncalarm set status = '"+ msg +"' where Time = '"+ last_send_time +"'";
                await db_util.query(sql);

                var status = (parseInt(used_time/allow_time) + 1) * allow_time;
                sql = "update cnctool set alarm_status = "+ status +" where id = "+ rows[0].id +"";
                await db_util.query(sql);
                console.log(sql);
              }
            }
          }
          else
          {
            send_alarm = true;
          }

          if( send_alarm == true )
          {
            var starttime = getMonthDayTime(date, 1, 1);
            sql = "刀号"+ array[i].tools[j].toolID +"使用时间超过" + allow_time + "小时";
            await execute_http_request(i, sql, level, starttime, name);
            alarm_count ++;
          }
        }
      }
    }
    if( alarm_count > 0 )
    {
      await addAlarmCount(alarm_count);
    }
  }
  catch(error)
  {
    console.log('刀号累计使用时间统计 error: ' + error.message + ' on ' + getMonthDayTime(date, 1, 1));
  }

  try
  {
    var sql = "select id, name, MachineName, Time from cncalarm where length(reason) = 0";
    let suc = await db_util.query(sql);
    if( suc.length > 0 )
    {
      var starttime = parseInt(suc[0].Time);
      var endtime = date.getTime();
      let ret = await query_qiyeweixin_huifu(starttime, endtime);
      var objs = eval(ret);
      /*if( objs.length > 0 )
      {
        console.log('企业微信回复：');
        console.log(ret);
      }*/
      for(var i=0; i<objs.length; i++)
      {
        if( objs[i].reason.length == 0 )
          continue;
        for(var k=0; k<suc.length; k++)
        {
          if( suc[k].Time == objs[i]["eventTime"] )
          {
            sql = "update cncalarm set reason = '"+ objs[i]["reason"] +"', pic = '"+ objs[i]["pic"] +"', replyDate = '"+ objs[i]["replyDate"] +"' where id = '"+ suc[k].id +"'";
            await db_util.query(sql);

            // 解除报警
            sql = "select * from cncother where name = '"+ suc[k].name +"'";
            let suc2 = await db_util.query(sql);
            if( suc2.length > 0 )
            {
              var msg = suc[k].MachineName + " 警报解除";
              await execute_http_request_2(suc2[0].value, msg);
              console.log(msg + ' 来自企业微信回复：' + objs[i].reason);
              sql = "delete from cncother where name = '"+ suc[k].name +"'";
              await db_util.query(sql);

              var alarm_time = parseInt(suc2[0].reserved); // 第一次报警的时间，同时作为cncalarm表中的记录识别标记
              msg = getMonthDayTime(date, 1, 1) + " 警报解除 企业微信回复：见reason栏位";
              sql = "update cncalarm set status = '"+ msg +"' where Time = '"+ alarm_time +"'";
              await db_util.query(sql);

              // 报警次数加1
              var alarm_count = 1;
              await addAlarmCount(alarm_count);
            }
            break;
          }
        }
      }
    }
  }
  catch(error)
  {
    console.log('查询企业微信回复 error: ' + error.message + ' on ' + getMonthDayTime(date, 1, 1));
  }
}

async function isIdleTime(date)
{
  var hour = date.getHours();
  var currTime = date.getTime();
  let suc3 = await db_util.query("select * from cnctime");
  for(var i=0; i<suc3.length; i++)
  {
    var st = parseInt(suc3[i].starttime);
    var et = parseInt(suc3[i].endtime);
    if( suc3[i].starttime.indexOf('-') > 0 )
      st = Date.parse(suc3[i].starttime);
    if( suc3[i].endtime.indexOf('-') > 0 )
      et = Date.parse(suc3[i].endtime);
    if( currTime >= st && currTime < et )
    {
      if( suc3[i].status == "0" ) // 休假
      {
        return true;
      }
      else
      {
        return false;
      }
    }
  }
  if( (currTime - g_lastUpdateTime) < g_nWaitTime ) // 周日还在加班，但没有设置
    return false;
  if( date.getDay() == 0 && hour >= 8 )
    return true;
  if( date.getDay() == 1 && hour < 8 )
    return true;
  return false;
}

async function intervalMonitorDataStream()
{
  var date = new Date();
  var name = 'datastream';
  var currTime = date.getTime();
  var time = currTime - g_lastUpdateTime;
  let suc = await db_util.query("select * from cncother where name = '"+ name +"'");
  if( time < g_nWaitTime )
  {
    if( suc.length == 0 )
      return;
    var msg = "CNC监控系统数据流中断 警报解除";
    await execute_http_request_2(suc[0].value, msg);
    sql = "delete from cncother where name = '"+ name +"'";
    await db_util.query(sql);

    var alarm_time = parseInt(suc[0].reserved); // 第一次报警的时间，同时作为cncalarm表中的记录识别标记
    msg = getMonthDayTime(date, 1, 1) + " 警报解除";
    sql = "update cncalarm set status = '"+ msg +"' where Time = '"+ alarm_time +"'";
    await db_util.query(sql);

    // 报警次数加1
    var alarm_count = 1;
    await addAlarmCount(alarm_count);
    return;
  }
  if( isIdleTime(date) == true )
    return;
  var level = 'L4';
  var starttime = getMonthDayTime(date, 1, 1);
  if( suc.length > 0 )
  {
    var obj = JSON.parse(suc[0].value);
    var last_send_time = parseInt(obj.eventTime);
    if( isNaN(last_send_time) )
      last_send_time = currTime;
    if( (currTime - last_send_time) < g_nWaitTime )
    {
      return;
    }
    var count = parseInt(suc[0].remark);
    if( isNaN(count) )
      count = 1;
    if( count >= 4 )
    {
      count = parseInt((currTime - last_send_time)/g_nWaitTime);
      if( (count % 10) == 0 )
        console.log('CNC监控系统数据流持续中断中。。。。。。' + starttime);
      return;
    }
    if( count >= 3 )
      level = 'L1';
    else if( count == 2 )
      level = 'L2';
    else
      level = 'L3';
  }
  await execute_http_request_datastream(0, "CNC监控系统数据流中断", level, starttime, name);
}

process.on('uncaughtException', (reason, p) => {
  var date = new Date();
  console.log('系统捕获异常: ', getMonthDayTime(date, 1, 1), ', at ', p,  ', ', reason);
});


//配置服务端口。如果没有指定hostname，这个服务器会接收任何ipv6主机的访问，否则使用ipv4。
//所以当只需要获取远程客户端的ip时，需要指定hostname参数为0.0.0.0。
var server = app.listen(8977, '0.0.0.0', function () {
  //var host = server.address().address;
  var port = server.address().port;
  var date = new Date();
  g_cncOeeMonthBusy = false;
  g_nWaitTime = 180 * 1000; // 最大等待时间：3分钟
  g_nOffTime = 600 * 1000;  // 最小关机时间间隔：10分钟
  g_lastUpdateTime = date.getTime() - g_nWaitTime * 2;
  setTimeout(function(){ setInterval(intervalMonitorDataStream, 60000); }, g_nWaitTime * 2);

  console.log(getMonthDayTime(date, 1, 1));
  console.log('fsms api listening port %s', port);

  httpServer.listen(8978);
  //var buf = Buffer.from("MTIzNDU2", "base64");
  //co1nsole.log(buf.toString());

  loadCNC();

  setInterval(intervalFunc, 297100); // 间隔5分钟左右
  
  setInterval(intervalAlarm, 148300); // 间隔2分半左右

  setTimeout(function() { kafkaTest(); }, 1000);
})

module.exports = app;
